简体   繁体   中英

Ignore chained calls in assert_has_calls with pytest mocker

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.

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