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
According to the python documentation https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.assert_called_with. 'This method is a convenient way of asserting that calls are made in a particular way' so it tests whether the parameters are being used in the correct way.
Mocking is simply the act of replacing the part of the application you are testing with a dummy version of that part called a mock. Instead of calling the actual implementation, you would call the mock, and then make assertions about what you expect to happen.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With