Assume we have a function f(x,y)
and another function
def g():
# ...
f(i,j) # i,j vary and f is called multiple times
# ...
We want to write a Unit test that checks whether f
is called the number of times and with the right parameters.
def test_g():
with patch('mymodule.f') as function:
assert function.gacs.call_count == correct_no_calls
There is
function.assert_called_with(...)
but this only refers to the last call. So assuming g
calls f(1,2)
and then f(2,3)
, function.assert_called_with(1,2)
is False
.
Furthermore, there is
function.call_args_list
which yields a list of call
objects with the right parameters. Comparing this list to call
object that we create in the unit test feels like a very nasty thing to do. call
seems like an internal class of the mock library.
Is there a better way to do this? I use this set-up to test parallel execution of an apply
function.
Even @MartinPieters's answer is correct I think that is not the best way to do it. Mock provide assert_has_calls
to do this kind of duties.
Your test could be:
function.assert_has_calls([mock.call(1, 2), mock.call(2, 3)])
Where mock.call
is a helper class do to these kind of jobs.
Pay attention that is a has call and means the call list should be in the list of call and not equal. To solve it I usually define my own helper assert_is_calls()
as follow
def assert_is_calls(m, calls, any_order=False):
assert len(m.mock_calls) == len(calls)
m.assert_has_calls(calls, any_order=any_order)
That a resume example
>>> import mock
>>> f = mock.Mock()
>>> f(1)
<Mock name='mock()' id='139836302999952'>
>>> f(2)
<Mock name='mock()' id='139836302999952'>
>>> f.assert_has_calls([mock.call(1), mock.call(2)])
>>> f.assert_has_calls([mock.call(2), mock.call(1)])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/damico/.local/lib/python2.7/site-packages/mock/mock.py", line 969, in assert_has_calls
), cause)
File "/home/damico/.local/lib/python2.7/site-packages/six.py", line 718, in raise_from
raise value
AssertionError: Calls not found.
Expected: [call(2), call(1)]
Actual: [call(1), call(2)]
>>> f.assert_has_calls([mock.call(2), mock.call(1)], any_order=True)
>>> f(3)
<Mock name='mock()' id='139836302999952'>
>>> f.assert_has_calls([mock.call(2), mock.call(1)], any_order=True)
>>> f.assert_has_calls([mock.call(1), mock.call(2)])
>>> assert len(f.mock_calls)==2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError
>>> assert len(f.mock_calls)==3
>>> def assert_is_calls(m, calls, any_order=False):
... assert len(m.mock_calls) == len(calls)
... m.assert_has_calls(calls, any_order=any_order)
...
>>> assert_is_calls(f, [mock.call(1), mock.call(2), mock.call(3)])
>>> assert_is_calls(f, [mock.call(1), mock.call(3), mock.call(2)])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in assert_is_calls
File "/home/damico/.local/lib/python2.7/site-packages/mock/mock.py", line 969, in assert_has_calls
), cause)
File "/home/damico/.local/lib/python2.7/site-packages/six.py", line 718, in raise_from
raise value
AssertionError: Calls not found.
Expected: [call(1), call(3), call(2)]
Actual: [call(1), call(2), call(3)]
>>> assert_is_calls(f, [mock.call(1), mock.call(3), mock.call(2)], True)
>>> assert_is_calls(f, [mock.call(1), mock.call(3)], True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in assert_is_calls
AssertionError
>>>
Test if the Mock().mock_calls
list is equal to a list of mock.call()
objects you provide:
self.assertEquals(function.mock_calls, [
mock.call(1, 2),
mock.call(2, 3),
])
This gives you precise control, requiring both the order and the number of calls to match.
The mock.call()
class is not internal, it is meant to be used for assertions like these.
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