简体   繁体   中英

Mocking assert_called_with in Python

I'm having some trouble understanding why the following code does not pass:

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

In the code, Foo.add creates an instance of Bar and returns the result of Bar.add when invoked. Why does testing assert_called_with for Bar.add fail? I believe I am mocking the Bar in the correct place (I am mocking foo.Bar because that is the namespace which it is being looked up, rather than bar.Bar ).

Traceback (most recent call last): File "/Users/iain/PycharmProjects/testing/venv/lib/python2.7/site-packages/mock.py", line 1201, in patched return func(*args, **keywargs) File "test.py", line 12, in test_a_b fake_Bar.add.assert_called_with(2, 2) File "/Users/iain/PycharmProjects/testing/venv/lib/python2.7/site-packages/mock.py", line 831, in assert_called_with raise AssertionError('Expected call: %s\\nNot called' % (expected,)) AssertionError: Expected call: add(2, 2) Not called

You are mocking the method call in the right place. However, since you are calling the method from an instance, it is a bound method, and thus receives the instance as the first argument (the self parameter), in addition to all the other arguments.

Edit : Since Bar is replaced with a Mock instance, Bar().add does not know it's a method (and hence is not bound to anything). In other words, Bar is a Mock , Bar() is a Mock , and Bar().add is also a Mock . bar.add is thus a newly created mock, called with arguments (2, 2) . One way of asserting this call would be:

@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)

Depending on how your actual code looks, you may want to instead mock the method rather than the class:

@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)

I believe your problem would be solved like this:

from bar import Bar

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM