Reputation: 174
In a unit test with mocked function, I would like to verify not only the count of arguments, but also that those conform the declared types of autospec-mocked function.
Here is the example code:
from unittest.mock import create_autospec
def foo(a: int, b: str):
return str(a) + b
mock_foo = create_autospec(foo)
foo = mock_foo # would be patched by e.g. @patch or monkeypatch fixture
foo(1, 2)
assert foo.called
This code tests that foo
is called correctly. e.g. such call would fail: foo(1,2,3)
This includes validation of arguments, but not of their types. Is there a way for autospec or another function to validate the types of passed arguments? This information is available in the signature of the method, so I imagine I could write myself such a validation using inspect
module. But is there something standard, a built-in or library?
Upvotes: 1
Views: 989
Reputation: 16215
This can be solved by adding a side_effect to your mock that compares arguments and annotations:
from unittest.mock import create_autospec
def check_params(method):
def cp(*args, **kwargs):
for arg, typ in zip(args, method.__annotations__.values()):
assert isinstance(arg, typ)
for k, v in kwargs.values():
assert isinstance(v, method.__annotations__[k])
return cp
def foo(a: int, b: str):
return str(a) + b
mock_foo = create_autospec(foo)
mock_foo.side_effect=check_params(foo)
foo = mock_foo # would be patched by e.g. @patch or monkeypatch fixture
foo(1, 2)
assert foo.called
This will raise an AssertionError because b
should be a str
but is an int
.
This could also be used with a class: from unittest.mock import create_autospec
def check_params(method):
def cp(*args, **kwargs):
for arg, typ in zip(args, method.__annotations__.values()):
assert isinstance(arg, typ)
for k, v in kwargs.values():
assert isinstance(v, method.__annotations__[k])
return cp
class Foo:
def foo(a: int, b: str):
return str(a) + b
mock_foo = create_autospec(Foo)
mock_foo.foo.side_effect=check_params(Foo.foo)
mock_foo.foo(1, 2)
assert mock_foo.foo.called
Upvotes: 0