【问题标题】:How to mock out custom throttle class for testing in django-rest-framework?如何模拟自定义油门类以在 django-rest-framework 中进行测试?
【发布时间】:2020-08-15 11:07:14
【问题描述】:

我有一个自定义限制类,例如:(打印语句用于调试 :))在 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 分钟)。

【问题讨论】:

  • 你想在第二次测试中模拟CustomThrottle,对吗?
  • @myuz,是的,在第一个测试中 allow_request 方法被模拟,但在第二个测试中,我希望整个 CustomThrottle 类被模拟。

标签: python django unit-testing testing django-rest-framework


【解决方案1】:

如果你还想模拟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",
        )

它将用mocked 替换您的real 对象,还请查看unittest.mock documentation,它将在将来为您提供帮助。

【讨论】:

  • 抱歉有一个错字,我使用了像@patch('api.views.CustomThrottle') 这样的补丁,但它并不是在模拟我的视图使用的类。
  • mocked_custom_throttle_instance 来自哪里?
  • 您在测试中定义mocked_custom_throttle_instance = MagicMock() 然后您将它返回为一个修补对象custom_throttle.return_value = mocked_custom_throttle_instance,它对您有帮助吗?
  • 我忘了说我用过这种方式,贴个答案;我建议你复习一下。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 2018-07-22
    • 2021-12-21
    相关资源
    最近更新 更多