# mod.py
def foo():
bar1("arg1")
bar2("arg2")
def bar1(x):
pass
def bar2(x):
pass
Suppose we want to test foo
, asserting that it calls bar1
and bar2
in that order. It's possible like this:
# 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"), "b2")
foo()
mock.assert_has_calls(
[
mocker.call.b1("arg1"),
mocker.call.b2("arg2"),
]
)
The mocker
fixture is from pytest-mock
plugin. Execute the MCVE with python -m pytest
.
It works, however this approach has a big flaw in practice. Should the signature of bar2
change (e.g. it's not defined directly in mod.py
but was imported from a third-party dependency), then foo
can become completely broken yet the tests can not detect such a change, because that dependency was mocked out in the first place.
If something upstream changed in bar2
, for example another argument is added:
def bar2(x, y):
pass
The tests still pass, but the library code is now broken:
>>> from mod import foo
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
bar2("arg2")
TypeError: bar2() missing 1 required positional argument: 'y'
The usual solution to this issue is to autospec your mocks. An autospec would cause foo()
to fail during the test, too, because bar2
is called with incompatible signature.
Updated library:
def foo():
bar1("arg1")
bar2("arg2x", "arg2y")
def bar1(x):
pass
def bar2(x, y):
pass
Updated test:
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"),
]
)
These tests now fail for reasons I don't understand.
E AssertionError: Calls not found.
E Expected: [call.b1('arg1'), call.b2('arg2x', 'arg2y')]
E Actual: [call.b1('arg1')]
Why did adding autospec break the attach_mock
feature? How should you assert the order of calls without losing autospec?
Aucun commentaire:
Enregistrer un commentaire