Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 943
Iain Avatar asked Jun 08 '15 20:06

Iain


People also ask

What is Assert_called_with in Python?

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.

What is mocking in Python?

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.


1 Answers

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)
like image 184
Felipe Avatar answered Sep 20 '22 13:09

Felipe