如何用pytest测试类的方法是否作为参数传入被Mock的方法?
如何用pytest测试类的方法是否作为参数传入被Mock的方法?
先还原下你的问题场景,你有这样的业务代码:
import concurrent.futures from PyQt5 import QtCore class MyTask(QtCore.QObject): def do(self): ... class Manager(QtCore.QObject): def __init__(self): super().__init__() self.worker_executor = concurrent.futures.ThreadPoolExecutor() def run_task(self): self.worker_executor.submit(MyTask().do)
你想用pytest+mock验证:调用manager.run_task()时,ThreadPoolExecutor.submit确实接收到了MyTask实例的do方法作为参数,但直接比较绑定方法和类函数会失败——因为你是把**绑定方法(bound method)和类原生函数(function)**做对比,二者本身就不是同一个对象,自然断言不通过。
解决方案:从绑定方法的本质入手验证
绑定方法其实是「类函数+实例」的组合体,我们可以提取它的核心属性来做精准断言,这里有三种常用的实现方式:
方法一:检查绑定方法的__func__和__self__属性
每个绑定方法都自带__func__属性(指向对应的类原生函数)和__self__属性(指向所属的实例),我们可以分别验证这两个属性:
def test_run_task_calls_submit_with_mytask_do(): manager = Manager() manager.worker_executor.submit = mock.Mock() manager.run_task() submitted_callable = manager.worker_executor.submit.call_args[0][0] # 验证传入的是MyTask实例的do方法 assert isinstance(submitted_callable.__self__, MyTask) assert submitted_callable.__func__ is MyTask.do
方法二:简化验证——检查方法名和实例类型
如果你不需要严格对应到类的原生函数,只需要确认是MyTask实例的do方法,可以直接检查方法名和实例类型:
def test_run_task_calls_submit_with_mytask_do(): manager = Manager() manager.worker_executor.submit = mock.Mock() manager.run_task() submitted_callable = manager.worker_executor.submit.call_args[0][0] assert submitted_callable.__name__ == "do" assert isinstance(submitted_callable.__self__, MyTask)
方法三:提前Mock MyTask类,精准控制实例
如果想更灵活地控制MyTask的实例,也可以先Mock整个MyTask类,这样就能直接断言传入的是我们预设的Mock实例方法:
def test_run_task_calls_submit_with_mytask_do(mocker): # Mock MyTask类 mock_mytask_cls = mocker.patch("__main__.MyTask") mock_instance = mock_mytask_cls.return_value manager = Manager() manager.worker_executor.submit = mock.Mock() manager.run_task() # 断言submit传入的是mock实例的do方法 manager.worker_executor.submit.assert_called_once_with(mock_instance.do)
这几种方式都能完美解决你遇到的绑定方法和类函数不相等的问题~
备注:内容来源于stack exchange,提问作者mike rodent
相关产品推荐
相关产品推荐

