unittest.mock.patch:单元测试中的上下文管理器与setUp / tearDown

时间:2014-09-29 12:31:57

标签: python python-unittest

似乎有两种方法可以使用unittest.mock.patch:一种方法更好吗?

使用上下文管理器和语句:

class MyTest(TestCase):
    def test_something(self):
        with patch('package.module.Class') as MockClass:
            assert package.module.Class is MockClass

或者从设置和tearDown / cleanup调用start和stop:

class MyTest(TestCase):
    def setUp(self):
        patcher = patch('package.module.Class')
        self.MockClass = patcher.start()
        self.addCleanup(patcher.stop)

    def test_something(self):
        assert package.module.Class is self.MockClass

上下文管理器版本的代码较少,因此可以更容易阅读。我有理由为什么我更喜欢使用TestCase setUp / tearDown基础设施?

2 个答案:

答案 0 :(得分:2)

setUp中更喜欢修补的主要原因是,如果您有多个需要修补该类的测试。在这种情况下,您需要在每个测试中复制with语句。

如果你只有一个需要补丁的测试,我更喜欢with语句以便于阅读。

答案 1 :(得分:2)

还有第三种使用它的方法,作为装饰者:

class MyTest(testcase):

    @unittest.mock.patch('package.module.Class')
    def test_something(self):
        assert package.module.Class is self.MockClass

这甚至更少的代码,但这可能不相关。

有一些注意事项:(1)(正如babbageclunk所指出的)如果您需要重用补丁,那么在setUp中构建一个补丁的简单无聊的调用是最好的,并且易于阅读。 (2)如果你想创建任何元编程设施,以便在运行测试时打开或关闭修补,那么装饰器方法将为你节省很多麻烦。在这种情况下,您可以编写其他装饰器,或使用全局变量(ick)来控制是否将修补程序装饰器应用于测试函数。如果它们嵌入在函数定义中,那么如果您想在运行测试时关闭修补,则必须手动处理它们。您可能想要这样做的一个简单原因仅仅是运行测试而不进行修补以引发大量故障并观察您尚未实现的部分(您的修补程序用于元编程补丁,实际上可以捕获这些问题并打印好{ {1}}您的例外,甚至生成包含此类内容的报告)。可能还有更多的理由要求对是否(以及在何种程度上)修补是否发送进行精确控制"已发送"在特定时间的测试套件中。

装饰器方法也很好用(a)它允许你以一种外面的方式隔离哪些补丁到哪个测试函数,但是没有将它提交给{{1并且(b)当给定函数需要给定的补丁时,它使读者非常清楚。

在这种情况下,上下文管理器版本似乎没有很多好处,因为它几乎不比装饰器版本更具可读性。但是,如果真的只有一个案例,或者只是一小部分特定案例,那么上下文管理器版本就可以了。