Python 2.7 mock / patch:理解assert_called_XYZ()

时间:2013-12-05 11:53:28

标签: python unit-testing python-2.7 mocking

我对Python和Python中的单元测试比较陌生。从Java世界我知道模拟的概念,但它似乎与我在Python中看到的大不相同。

我找到了这个指南,我发现它非常有用:http://www.voidspace.org.uk/python/mock/index.html

但是当我使用模拟的依赖关系编写我的(更复杂的)测试时,我注意到了一种暴力行为。 我决定创建一个简化的简单示例,它也不像我预期的那样工作。

看看这个,结果以及我作为评论添加的期望:

import unittest
from mock import patch, Mock, MagicMock

class BasicTest(unittest.TestCase):

    @patch("StringIO.StringIO")
    def testSomethingNotWorkingAsExpected(self, StringIOMock):
        StringIOMock.assert_called_once() # asserts, but why?

    @patch("StringIO.StringIO")
    def testSomethingSomehowWorking(self, StringIOMock):
        # self.instantiateStringIO() # intentionally commented out
        assert StringIOMock.called # does not assert (leading to failure of this test); as expected. If the above line is not commented, this asserts as expected.

    def instantiateStringIO(self):
        import StringIO
        StringIO.StringIO()

为什么assert_called_once()断言StringIO的实例化,即使它尚未实例化? 为什么assert ClassMock.called会带来预期的结果?

使用assert not ...断言方法尚未调用我在此处找到:Assert a function/method was not called using Mock。我省略了not

,在我的案例中颠倒了这种模式

在某处我找到了引用实例的模式ClassMock.return_value。但我理解这是一种在调用Mock之前对其进行管理的方法,而不是作为访问可能是内部创建的底层代码的实例的方法。还是我错了?

我的环境:

  • Python 2.7.3
  • mock 0.8.8
  • Fedora 19

可能我对模拟/补丁的理解是错误的。可以请某人在某种程度上解释一下类模拟的作用以及它是如何工作的吗?

编辑1:添加输出

...并在parens中添加释义以在testSomethingSomehowWorking

中发表评论

这是输出:

.F
======================================================================
FAIL: testSomethingSomehowWorking (test_test.BasicTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/mock.py", line 1224, in patched
    return func(*args, **keywargs)
  File "test_test.py", line 15, in testSomethingSomehowWorking
    assert StringIOMock.called # does not assert; as expected
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

1 个答案:

答案 0 :(得分:12)

方法assert_called_once不存在,并且不执行断言。它与编写StringIOMock.assert_foo_bar_does_not_exist()或任何其他方法没有什么不同。模拟库不会检查模拟上调用的方法是否确实存在。

如果您使用assert_called_once_with,则会按预期失败。

当您调用不存在的方法时,可以使用spec参数引发错误:

@patch("StringIO.StringIO", spec=StringIO.StringIO)
def testSomethingNotWorkingAsExpected(self, StringIOMock):
    StringIOMock.assert_called_once() # will fail as the method doesn't exist