如何正确使用django测试用例的addCleanup方法?

时间:2019-09-08 10:49:59

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

我有一个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方法中。

有人看到我在搞砸吗?

2 个答案:

答案 0 :(得分: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))

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

以下代码应该类似于:

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

答案 1 :(得分:0)

方法名称为setUp(self),因为测试框架会寻找此方法,所以您不能仅仅更改它。

更改为

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

    @classmethod
    def setUpTestData(cls):
        ...