覆盖Python mock的补丁装饰器

Gab*_*abe 15 python testing mocking

我有一个Python TestCase类,除了一个测试方法之外,所有测试方法都需要以相同的方式修补对象.另一种方法需要来自同一对象的一些其他行为.我正在使用模拟,所以我做了:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    @mock.patch('method_to_patch', mock.Mock(return_value=2))
    def test_override(self):
         (....)
Run Code Online (Sandbox Code Playgroud)

但那不起作用.当test_override运行时,它仍然要求从类装饰修补的行为.

经过大量的调试后,我发现在TestSuite构建期间,@patch周围的周围test_override被调用Tests,并且由于mock按顺序应用补丁,类装饰器会覆盖方法装饰器.

这个订单是否正确?我期待相反的情况,我不确定如何覆盖修补...也许有一个with声明?

Gab*_*abe 24

好吧,事实证明,良好的睡眠和冷水淋浴使我重新思考整个问题.我对嘲讽的概念还很陌生,所以它仍然没有完全正确地沉没.

问题是,没有必要将补丁覆盖到模拟对象.这是一个模拟对象,这意味着我可以做任何事情.所以我的第一次尝试是:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         method_to_patch.return_value = 2
         (....)
Run Code Online (Sandbox Code Playgroud)

这有效,但有副作用,改变所有后续测试的返回值.那么我试过:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         method_to_patch.return_value = 2
         (....)
         method_to_patch.return_value = 1
Run Code Online (Sandbox Code Playgroud)

它就像一个魅力.但似乎代码太多了.那么我就走上了上下文管理的道路,就像这样:

@mock.patch('method_to_patch', mock.Mock(return_value=1))
class Tests(TestCase):

    def test_override(self):
         with mock.patch('method_to_patch', mock.Mock(return_value=2):
             (....)
Run Code Online (Sandbox Code Playgroud)

我觉得它看起来更清晰,更简洁.

关于patch装饰器的应用顺序,它实际上是正确的顺序.就像从下到上应用堆叠装饰器一样,应该在类装饰器之前调用方法装饰器.我想这很有道理,我只是期待相反的行为.

无论如何,我希望这将有助于一些像我一样可怜的新手灵魂.