【问题标题】:How to properly use django testcase's addCleanup method?如何正确使用 django 测试用例的 addCleanup 方法?
【发布时间】:2020-01-10 11:13:18
【问题描述】:

我有一个 APITestCase 的测试子类,我使用类方法 setUpTestData 为我的测试和一些模拟创建数据。基本上我想做的是运行 mock.patch.stopall (如下所示),但它不起作用。

我的实现基于THIS ANSWER,我正在使用:Django v2.2.4 和 djangorestframework v3.10.2

import mock
from rest_framework.test import APITestCase


class FooTest(APITestCase):

    @classmethod
    def setUpTestData(cls):
        patcher_one = mock.patch('route.one')
        mock_route_one = patcher_one.start()

        patcher_two = mock.patch('route.two')
        mock_route_one = patcher_two.start()

        cls.addCleanup(mock.patch.stopall)

        # etc

        super(FooTest, cls).setUpTestData()

使用此代码运行测试时,我得到:

TypeError: addCleanup() missing 1 required positional argument: 'function'

所以我将 addCleanup 调用编辑为:

cls.addCleanup(function=mock.patch.stopall)

但我得到以下信息:

TypeError: addCleanup() missing 1 required positional argument: 'self'

编辑到:

cls.addCleanup(cls, function=mock.patch.stopall)

我明白了

AttributeError: type object 'FooTest' has no attribute '_cleanups'

此时我有点迷茫。

我正在使用的解决方法是在 tearDownClass 方法中进行:

@classmethod
def tearDownClass(cls):
    mock.patch.stopall()

但我想把所有的测试逻辑集中在 setUpTestData 方法中。

有人知道我在哪里搞砸了吗?

【问题讨论】:

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


    【解决方案1】:

    没有实例就不能调用实例方法。 Django 的 setUpTestData 是一个类方法。

    addCleanUp 的代码(Django 子类 Unittest.TestCase):

    def addCleanup(self, function, *args, **kwargs):
        """Add a function, with arguments, to be called when the test is
        completed. Functions added are called on a LIFO basis and are
        called after tearDown on test failure or success.
    
        Cleanup items are called even if setUp fails (unlike tearDown)."""
        self._cleanups.append((function, args, kwargs))
    

    您应该做的是将您的模拟移动到 setup 方法。首先,您应该调用 self.addcleanup(patch.stopall) 以确保即使 setup 方法中发生错误(有时可能)也会停止模拟,然后开始模拟。这在 python 文档的here 中有解释。

    下面的代码应该类似于:

    class FooTestCase(TestCase):
        def setUp(self):
            super().setUp()
            self.addCleanup(patch.stopall)
            patch('route.one').start()
    

    【讨论】:

      【解决方案2】:

      方法名称是setUp(self),您不能只更改它,因为测试框架会寻找该方法来运行。

      改成

      class FooTest(APITestCase):
          @classmethod
          def setUp(cls):
              ...
              cls.addCleanup(mock.patch.stopall)
      
          @classmethod
          def setUpTestData(cls):
              ...
      

      【讨论】:

      • 据我了解,在这种情况下,我们在运行类中的每个测试之前调用 addCleanup。无论如何,我仍然对这个解决方案有同样的问题。
      • 这个答案不正确,因为setUp 是实例方法,而不是类方法。 addCleanUp 也是如此 - 它是一个实例方法,因此在没有实例时您不能调用实例方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-18
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多