【问题标题】:Proper way to mock classes and assert on calls to methods模拟类和断言方法调用的正确方法
【发布时间】:2016-03-08 03:09:47
【问题描述】:

我正在尝试为Bar 编写单元测试,以调用Foo 的方法read()。我在setUp() 中添加了patch 命令,因为其他测试也会使用这个patch。

问题

如何检查 read() 函数是否使用我期望的参数调用?

代码

foo.py
class Foo(object):
    def __init__(self):
        self.table = {'foo': 1}

    def read(self, name):
        return self.table[name]
bar.py
import foo

class Bar(object):
    def act(self):
        a = foo.Foo()
        return a.read('foo')
test_bar.py
import bar
import unittest
from mock import patch

class TestBar(unittest.TestCase):
    def setUp(self):
        self.foo_mock = patch('bar.foo.Foo', autospec=True).start()
        self.addCleanup(patch.stopall)

    def test_can_call_foo_with_correct_arguments(self):
        a = bar.Bar()
        a.act()
        self.foo_mock.read.assert_called_once_with('foo')

输出

python -m unittest discover
F
======================================================================
FAIL: test_can_call_foo_with_correct_arguments (test_bar.TestBar)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/test_dir/test_bar.py", line 12, in test_can_call_foo_with_correct_arguments
    self.foo_mock.read.assert_called_once_with('foo')
  File "/usr/local/lib/python2.7/dist-packages/mock.py", line 845, in assert_called_once_with
    raise AssertionError(msg)
AssertionError: Expected to be called once. Called 0 times.

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

【问题讨论】:

  • 你试过了吗? self.foo_mock.return_value.read.assert_called_once_with('foo')?
  • 您可以尝试使用真正的 foo self.foo = Foo(),然后模拟读取调用:self.foo.read = Mock()?
  • 或patch.object 可能是您正在寻找的stackoverflow.com/a/5044894/1389752
  • @SimeonVisser 你是对的。对于这个最小的例子,我忘记在我的测试中调用a.act()。谢谢!我也更新了问题

标签: python python-2.7 unit-testing mocking python-unittest


【解决方案1】:

read 是Foo 的instances 上的一个方法。您想检查模拟 return_value 以访问实例。毕竟,您通过调用 foo.Foo():

创建实例
foo_instance = self.foo_mock.return_value
foo_instance.read.assert_called_once_with('foo')

请注意,您正在修补foo.Foo; using bar.foo.Foo 是同一个对象,但指定它的方式是迂回的。

【讨论】:

    【解决方案2】:

    Mocks 有很多陷阱,这就是为什么 I wrote a helper library 为我生成断言。

    要使用它,你应该在a.act()之后添加以下行:

    import mock_autogen.generator
    print(mock_autogen.generator.generate_asserts(mock=self.foo_mock, name='self.foo_mock'))
    

    这会输出这些行:

    assert 1 == self.foo_mock.call_count
    self.foo_mock.assert_called_once_with()
    self.foo_mock.return_value.read.assert_called_once_with('foo')
    

    生成前两个是因为 foo 是一个被实例化的类。第三行是您最初要查找的行。

    所以不要再猜测了,有条不紊地使用mock-generator。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多