Как создать собственный класс газа для тестирования в django -rest-framework? - PullRequest
4 голосов
/ 01 мая 2020

У меня есть собственный класс газа, например: (операторы print предназначены для отладки :) ) в api.throttle.py

print("befor CustomThrottle class")
class CustomThrottle(BaseThrottle):
    def __init__(self):
        super().__init__()
        print("initializing CustomThrottle", self)
        self._wait = 0

    def allow_request(self, request, view):
        print("CustomThrottle.allow_request")
        if request.method in SAFE_METHODS:
            return True
        # some checking here
        if wait > 0:
            self._wait = wait
            return False
        return True

    def wait(self):
        return self._wait

my api.views.py is как:

from api.throttle import CustomThrottle

print("views module")
class SomeView(APIView):
    print("in view")
    throttle_classes = [CustomThrottle]

    def post(self, request, should_exist):
        # some processing
        return Response({"message": "Done."})

и мои тесты api/tests/test_views.py:

    @patch.object(api.views.CustomThrottle, "allow_request")
    def test_can_get_confirmation_code_for_registered_user(self, throttle):
        throttle.return_value = True
        response = self.client.post(path, data=data)
        self.assertEqual(
            response.status_code,
            status.HTTP_200_OK,
            "Should be successful",
        )

    @patch("api.views.CustomThrottle")
    def test_learn(self, throttle):
        throttle.return_value.allow_request.return_value = True
        response = self.client.post(path, data=data)
        self.assertEqual(
            response.status_code,
            status.HTTP_200_OK,
            "Should be successful",
        )

первый тест проходит правильно, но класс CustomThrottle все еще создается, но метод allow_request является ложным; второй тест показывает, что ни класс CustomThrottle не является поддельным, ни метод allow_request, и он не работает с status 429 (CustomThrottle имеет скорость дроссельной заслонки 2 минуты).

Ответы [ 2 ]

0 голосов
/ 03 мая 2020

Потратив некоторое время и протестировав другой сценарий ios (Размещая отладочные сообщения типа print тут и там :) ) Наконец-то я понял, почему он не работает, Но это может быть не так корректно, как мне кажется, поэтому лучше ответить на любой лучший ответ .

Я определил список классов газа, например throttle_classes = [CustomThrottle], поэтому при запуске сервера он импортируется и оценивается, поэтому есть ссылка на фактическая и немодулированная версия CustomThrottle в моем классе SomeView, и при обработке ответов он будет использовать ее для создания экземпляра, поэтому мой тест не пройден, но когда я исправляю его как patch.object(CustomThrottle, "allow_request"), когда view действительно нужно проверить дроссели, он вызовет что-то вроде CustomThrottle().allow_request(...) (обратите внимание на круглые скобки для создания объекта); у объекта нет такого метода, как allow_request, поэтому он ищет его в своем классе и правильно использует макетированную версию.

0 голосов
/ 03 мая 2020

Если вы хотите также высмеивать CustomThrottle класс и его свойства, вам также нужно patch в тех местах, где вам это нужно, потому что patch декоратор применяет monkey patching в тех местах, где вы его вызываете.

Что касается вашего случая, вы можете сделать что-то вроде

from unittest.mock import MagicMock, patch

    @patch('api.views.CustomThrottle')
    @patch('api.views.PhoneConfirmationThrottle')
    def test_learn(self, phone_throttle, custom_throttle):
        mocked_custom_throttle_instance = MagicMock()
        mocked_custom_throttle_instance.allow_request = True
        mocked_custom_throttle_instance.status = ...

        # Do some stuff which do you need with the mocked class
        # and then return an instance for your patched object

        custom_throttle.return_value = mocked_custom_throttle_instance

        response = self.client.post(path, data=data)
        self.assertEqual(
            response.status_code,
            status.HTTP_200_OK,
            "Should be successful",
        )

Это заменит ваш real объект на mocked, также посмотрите документацию unittest.mock , это поможет вам в будущем.

...