【问题标题】:Mocking assert_called_with in Python在 Python 中模拟 assert_call_with
【发布时间】:2015-06-08 20:20:11
【问题描述】:

我无法理解为什么以下代码没有通过:

test.py

import mock
import unittest

from foo import Foo


class TestFoo(unittest.TestCase):
    @mock.patch('foo.Bar')
    def test_foo_add(self, Bar):
        foo = Foo()
        foo.add(2, 2)
        Bar.add.assert_called_with(2, 2)


if __name__ == '__main__':
    unittest.main()

foo.py

from bar import Bar

class Foo(object):
    def add(self, x, y):
        bar = Bar()
        return bar.add(x, y)

bar.py

class Bar(object):
    def add(self, x, y):
        print('b.Bar --> Adding {} + {}'.format(x, y))
        return x + y

在代码中,Foo.add 创建了一个Bar 的实例,并在调用时返回Bar.add 的结果。为什么为Bar.add 测试assert_called_with 会失败?我相信我在正确的地方嘲笑Bar(我在嘲笑foo.Bar,因为这是它正在查找的命名空间,而不是bar.Bar)。

Traceback(最近一次调用最后一次): 文件“/Users/iain/PycharmProjects/testing/venv/lib/python2.7/site-packages/mock.py”,第 1201 行,已修补 返回函数(*args,**keywargs) 文件“test.py”,第 12 行,在 test_a_b fake_Bar.add.assert_call_with(2, 2) 文件“/Users/iain/PycharmProjects/testing/venv/lib/python2.7/site-packages/mock.py”,第 831 行,在 assert_called_with raise AssertionError('预期调用: %s\n未调用' % (expected,)) AssertionError:预期调用:add(2, 2) 未调用

【问题讨论】:

    标签: python unit-testing mocking


    【解决方案1】:

    您在正确的位置模拟方法调用。但是,由于您是从一个实例调用该方法,它是一个绑定方法,因此除了所有其他参数之外,还接收该实例作为第一个参数(self 参数)。

    编辑:由于Bar 被替换为Mock 实例,Bar().add 不知道它是一种方法(因此不受任何约束)。换句话说,BarMockBar()MockBar().add 也是 Mockbar.add 因此是一个新创建的模拟,使用参数(2, 2) 调用。断言此调用的一种方法是:

    @mock.patch('foo.Bar')
    def test_foo_add(self, Bar):
        foo = Foo()
        foo.add(2, 2)
        Bar.return_value.add.assert_called_with(2, 2)
    

    根据实际代码的外观,您可能希望模拟方法而不是类:

    @mock.patch('foo.Bar.add')
    def test_foo_add(self, bar_add):
        foo = Foo()
        foo.add(2, 2)
        bar_add.assert_called_with(2, 2)
    

    【讨论】:

    • 我已经修改了测试,将foo 作为第一个参数传递给Bar.add.assert_called_with(),但测试仍然失败?输出内容相同(AssertionError: Expected call: add(, 2, 2) Not called)
    • 糟糕,我的示例代码完全错误。将更新一些正确的答案。对不起!
    • 谢谢!我想我犯了一个错误,认为如果我嘲笑foo.Bar,那么它的所有属性和方法都保持不变,除非我明确改变它们的行为。这会是一种可能使用mock.patch.object 方法的情况吗?
    • patch.objectpatch 具有相同的功能;他们只是使用不同的方式来引用要修补的对象。要在foo 模块中修补Bar,您将使用mock.patch(foo, 'Bar'),结果将是相同的。不幸的是,我不知道有一种预先构建的方式来获得你想要的行为。
    【解决方案2】:

    我相信你的问题会这样解决:

    from bar import Bar
    
    class Foo(object):
        def add(self, x, y):
            self.bar = Bar()
            return self.bar.add(x, y)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-27
      • 2015-09-07
      相关资源
      最近更新 更多