24

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

@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):
         (....)

但这行不通。运行时test_override,它仍然从类装饰器调用修补的行为。

经过大量调试,我发现在TestSuite构建过程中,@patcharoundtest_override是在 around 之前调用的Tests,并且由于mock按顺序应用补丁,类装饰器覆盖了方法装饰器。

这个顺序正确吗?我期待相反的情况,我不确定如何覆盖补丁......也许有一个with声明?

4

1 回答 1

35

好吧,事实证明,睡个好觉和洗个冷水澡让我重新思考了整个问题。我对嘲笑的概念还很陌生,所以它还没有完全正确。

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

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

    def test_override(self):
         method_to_patch.return_value = 2
         (....)

这有效,但具有更改所有后续测试的返回值的副作用。所以我尝试了:

@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

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

@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):
             (....)

我认为它看起来更清晰,更简洁。

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

无论如何,我希望这对将来像我这样的可怜的新手灵魂有所帮助。

于 2012-10-09T16:08:02.203 回答