问题
Library module:
# mod.py
def foo():
bar1("arg1")
bar2("arg2x", "arg2y")
def bar1(x):
pass
def bar2(x, y):
pass
Test module:
# test_mod.py
from mod import foo
def test_foo(mocker):
mock = mocker.MagicMock()
mock.attach_mock(mocker.patch("mod.bar1"), "b1")
mock.attach_mock(mocker.patch("mod.bar2", autospec=True), "b2")
foo()
mock.assert_has_calls(
[
mocker.call.b1("arg1"),
mocker.call.b2("arg2x", "arg2y"),
]
)
The mocker
fixture is from pytest-mock plugin. Execute the MCVE with python -m pytest
.
This test fails for weird reasons.
E AssertionError: Calls not found.
E Expected: [call.b1('arg1'), call.b2('arg2x', 'arg2y')]
E Actual: [call.b1('arg1')]
Without the autospec it works. Does using autospec break the attach_mock
feature? How should the test for foo
assert on the order and args of the calls to dependencies bar1
and bar2
without losing their autospec?
回答1:
This was actually a bug in Python. It got fixed in late 2019, patched versions:
- Python 3.8.2+
- Python 3.7.5+
The test in original post is now passing on a fixed version. No backport for Python 3.6, which is security only now so will remain bugged forever. 🐛
These are the related PRs and issue tracker links:
bpo-21478: Autospec functions should propagate mock calls to parent
bpo-21478: Record calls to parent when autospecced objects are used as child with attach_mock
bpo-38473: Handle autospecced functions and methods used with attach_mock
Patch by Karthikeyan Singaravelan.
来源:https://stackoverflow.com/questions/56367526/cannot-use-attach-mock-with-an-autospec-function-mock