如何在Djangorest框架中模拟定制节流类进行测试?

2024-09-30 00:27:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个定制的throttle类,比如:(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

我的api.views.py是这样的:

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分钟)


Tags: selfapitruedatareturnresponserequestdef
2条回答

如果您还想模拟CustomThrottle类及其属性,那么您还需要在需要它的地方patch,因为patchdecorator在调用它的地方应用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",
        )

它将用mocked对象替换您的real对象,也可以签出unittest.mock documentation,它将在将来帮助您

在花了一些时间并测试了不同的场景(在这里和那里放置类似调试的打印语句)之后,我终于找到了它不起作用的原因,,但它可能没有我认为的那么正确,所以欢迎任何更好的答案

我定义了throttle_classes = [CustomThrottle]等节流类的列表,所以当服务器启动时,它会被导入和评估,所以在我的SomeView类中有一个对CustomThrottle的实际版本和未修改版本的引用,当处理响应时,它会将其用于实例化,因此我的测试失败,但当我像patch.object(CustomThrottle, "allow_request")一样修补它时当视图实际需要检查节流时,它将调用类似CustomThrottle().allow_request(...)(注意对象创建时的括号);对象本身没有类似allow_request的方法,因此它在其类中搜索该方法并正确使用模拟版本

相关问题 更多 >

    热门问题