mock异步方法时assert_called_once_with为何出现不同对象ID?
问题根因
你遇到的协程对象内存ID不一致问题,本质是AsyncMock的调用特性导致的:
- 被
mocker.patch替换的异步方法会生成AsyncMock实例,每次调用AsyncMock都会生成一个全新的协程对象,哪怕入参完全一致,不同次调用生成的协程内存地址也不相同。 - 业务代码执行
self.func_to_be_mocked(x, y)时,生成了第一个协程对象,作为参数传给了create_task,这是真实传入的入参。 - 你在断言语句里写的
mocked_func(1, 2),会触发AsyncMock的第二次调用,生成第二个全新的协程对象,拿这个新生成的对象去和之前的实际入参做匹配,必然会出现内存ID不一致、断言失败的问题。 - 你的测试代码还存在两个额外问题:一是断言中使用的
mocked_func_to_be_mocked变量并未定义,你实际声明的mock变量名为mocked_func;二是mocked_func.return_value = mocked_func属于无效写法,异步mock的return_value是协程执行完成后的返回结果,不需要赋值为mock对象本身,这行可以直接删除。
正确修复方案
你不需要手动调用mock方法生成协程来做参数匹配,正确的校验逻辑分两步即可:
- 校验被mock的异步方法
func_to_be_mocked确实被正确的参数调用过 - 校验
create_task确实被调用,且传入的参数是合法协程对象
参考实现代码:
import asyncio from unittest.mock import ANY class Tests(): def test_func_to_be_tested(self, mocker): test_class = ClassUnderTest() mocked_func = mocker.patch("class_under_test.ClassUnderTest.func_to_be_mocked") mocked_event_loop = mocker.patch("asyncio.AbstractEventLoop") mocked_task = mocker.patch("asyncio.Task") mocker.patch("asyncio.new_event_loop", return_value=mocked_event_loop) mocker.patch("asyncio.AbstractEventLoop.create_task", return_value=mocked_task) test_class.func_to_be_tested(1, 2) # 校验异步方法被正确参数调用 mocked_func.assert_called_once_with(1, 2) # 校验create_task调用逻辑,写法1:显式校验传入参数是协程 mocked_event_loop.create_task.assert_called_once() call_args, _ = mocked_event_loop.create_task.call_args assert asyncio.iscoroutine(call_args[0]) # 校验create_task调用逻辑,写法2:更简洁的ANY匹配 # mocked_event_loop.create_task.assert_called_once_with(ANY)
内容的提问来源于stack exchange,提问作者Lexie-fox
相关产品推荐
相关产品推荐

