如何无需重新调用获取未Mock函数的原始return_value?
问题:Mock异步函数时如何获取原始返回值用于断言?
我查阅了相关文档,但没找到怎么访问foo_hello函数的原始/预期/未修改的return_value来做断言。目前想到的最优方案是从call_args里取参数重新调用函数。用side_effect的时候确实会调用foo_hello,但查看foo.return_value只能拿到AsyncMock对象。有没有不用重新调用函数就能获取返回值的方法?
另外想问:Mock函数/对象的return_value能不能和未Mock时函数运行的预期返回值一致?我试过设置wraps为foo_hello,效果和side_effect差不多。
示例代码:
from unittest.mock import patch import pytest async def foo_hello(x, y): return {f"hello {z}":f"world {y}"} # 注:原代码中z应为x,属于笔误 @pytest.mark.asyncio async def test(client: AsyncClient): payload = {"foo": "bar", "hello": "world"} with patch( "module.foo_hello",side_effect=foo_hello ) as foo, patch( "module.create_pool", return_value=MockArqRedis(), ): # handler function calls foo_hello down stream response = await handler_function( request=payload, user_id=user.id, ) foo.assert_called_once_with( x=some_value, y=some_value, ) parameters = foo.call_args[1] foo_return: dict = await foo(**parameters) assert "some_value" in foo_return
解决方案
1. 自定义side_effect捕获返回值
不用重新调用函数,直接在side_effect里把原始函数的返回值存下来,后续直接使用即可:
from unittest.mock import patch import pytest async def foo_hello(x, y): return {f"hello {x}": f"world {y}"} # 修正原代码的z笔误 @pytest.mark.asyncio async def test(client: AsyncClient): payload = {"foo": "bar", "hello": "world"} # 用于存储原始函数的返回值 captured_return = None async def capture_result(*args, **kwargs): nonlocal captured_return result = await foo_hello(*args, **kwargs) captured_return = result return result with patch( "module.foo_hello", side_effect=capture_result ) as foo, patch( "module.create_pool", return_value=MockArqRedis() ): await handler_function(request=payload, user_id=user.id) foo.assert_called_once_with(x=some_value, y=some_value) # 直接用捕获的返回值做断言 assert "some_value" in captured_return
2. 关于return_value与原始返回值同步的问题
Mock对象的return_value是预设的固定返回值,和side_effect/wraps的动态调用逻辑是分开的——即使你用wraps或者side_effect指向原始函数,return_value也不会自动同步原始函数的返回结果。
如果硬要让return_value等于原始返回值,只能像上面那样手动捕获后赋值,但完全没必要,直接用捕获返回值的方式更直接高效。
内容的提问来源于stack exchange,提问作者Hyperion
相关产品推荐
相关产品推荐

