Python 2.7 mock/patch:理解assert_called_XYZ()

try*_*lly 16 python unit-testing mocking python-2.7

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

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

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

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

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()
Run Code Online (Sandbox Code Playgroud)

为什么assert_called_once()断言实例化StringIO甚至还没有实例化呢?为什么会assert ClassMock.called带来预期的结果呢?

使用assert not ...断言的方法还没有被调用,我发现在这里:断言使用模拟函数/方法不叫.在我的情况下,我通过省略了这个模式not.

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

我的环境:

  • Python 2.7.3
  • 模拟0.8.8
  • Fedora 19

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

Edit1:添加输出

...并在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)
Run Code Online (Sandbox Code Playgroud)

Sim*_*ser 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
Run Code Online (Sandbox Code Playgroud)