When using mocker
from pytest-mock
, how can I use has_calls
to check the calls to a specific method without checking all the calls made to the return value of that method?
For example:
import subprocess
from unittest import mock
def test_foo(mocker):
m = mocker.patch('test_main.subprocess')
r1 = subprocess.run(['foo'])
r1.check_returncode()
r2 = subprocess.run(['bar'])
r2.check_returncode()
m.run.assert_has_calls([
mock.call(['foo']),
mock.call(['bar']),
])
Fails with:
E AssertionError: Calls not found.
E Expected: [call(['foo']), call(['bar'])]
E Actual: [call(['foo']),
E call().check_returncode(),
E call(['bar']),
E call().check_returncode()]
Why are calls to the return value also included? I just want to check that I had a call to subprocess.run(['foo'])
followed by a call to subprocess.run(['bar'])
. I don't care about calls made to anything it returns, but I do care about the order of calls to run
itself.
Add any_order=True
to your assert_has_calls
call, like this:
m.run.assert_has_calls([
mock.call(['foo']),
mock.call(['bar']),
], any_order=True)
The reason is, it looks like assert_has_calls
uses the mock_calls
attribute on a mock which based on the documentation ( https://docs.python.org/3/library/unittest.mock.html#unittest.mock.Mock.mock_calls ):
records all calls to the mock object, its methods, magic methods and return value mocks.
With assert_has_calls
though, it's not an exact matching problem it was just the ordering that was failing.
EDIT: Since order matters, use call_args_list
. Like this:
def test_foo(mocker):
m = mocker.patch('subprocess_test.subprocess')
r1 = subprocess.run(['foo'])
r1.check_returncode()
r2 = subprocess.run(['bar'])
r2.check_returncode()
assert [mock.call(['foo']), mock.call(['bar'])] == m.run.call_args_list
Use assert_any_call
:
m.run.assert_any_call(['foo'])
m.run.assert_any_call(['bar'])
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.