Skip to content

Commit 06d1848

Browse files
committed
Fix #178: handle spy on async functions
1 parent 2abec3b commit 06d1848

File tree

4 files changed

+36
-3
lines changed

4 files changed

+36
-3
lines changed

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
description="Thin-wrapper around the mock package for easier use with pytest",
2020
long_description=open("README.rst", encoding="utf-8").read(),
2121
keywords="pytest mock",
22-
extras_require={"dev": ["pre-commit", "tox"]},
22+
extras_require={"dev": ["pre-commit", "tox", "pytest-asyncio"]},
2323
classifiers=[
2424
"Development Status :: 5 - Production/Stable",
2525
"Framework :: Pytest",

src/pytest_mock/plugin.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import functools
23
import inspect
34

@@ -96,7 +97,6 @@ def spy(self, obj, name):
9697
if isinstance(value, (classmethod, staticmethod)):
9798
autospec = False
9899

99-
@functools.wraps(method)
100100
def wrapper(*args, **kwargs):
101101
spy_obj.spy_return = None
102102
spy_obj.spy_exception = None
@@ -109,7 +109,24 @@ def wrapper(*args, **kwargs):
109109
spy_obj.spy_return = r
110110
return r
111111

112-
spy_obj = self.patch.object(obj, name, side_effect=wrapper, autospec=autospec)
112+
async def async_wrapper(*args, **kwargs):
113+
spy_obj.spy_return = None
114+
spy_obj.spy_exception = None
115+
try:
116+
r = await method(*args, **kwargs)
117+
except Exception as e:
118+
spy_obj.spy_exception = e
119+
raise
120+
else:
121+
spy_obj.spy_return = r
122+
return r
123+
124+
if asyncio.iscoroutinefunction(method):
125+
wrapped = functools.update_wrapper(async_wrapper, method)
126+
else:
127+
wrapped = functools.update_wrapper(wrapper, method)
128+
129+
spy_obj = self.patch.object(obj, name, side_effect=wrapped, autospec=autospec)
113130
spy_obj.spy_return = None
114131
spy_obj.spy_exception = None
115132
return spy_obj

tests/test_pytest_mock.py

+15
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,21 @@ def __call__(self, x):
405405
assert spy.spy_return == 20
406406

407407

408+
@pytest.mark.asyncio
409+
async def test_instance_async_method_spy(mocker):
410+
class Foo:
411+
async def bar(self, arg):
412+
return arg * 2
413+
414+
foo = Foo()
415+
spy = mocker.spy(foo, "bar")
416+
417+
result = await foo.bar(10)
418+
419+
spy.assert_called_once_with(10)
420+
assert result == 20
421+
422+
408423
@contextmanager
409424
def assert_traceback():
410425
"""

tox.ini

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ envlist = py{35,36,37,38}, linting, norewrite
55
passenv = USER USERNAME
66
deps =
77
coverage
8+
pytest-asyncio
89
commands =
910
coverage run --append --source={envsitepackagesdir}/pytest_mock -m pytest tests
1011

0 commit comments

Comments
 (0)