如何在Python中监视类的实例化及方法调用?
我明白你的问题了——你想在运行原始类代码的同时,既跟踪类的实例化过程,又监控实例方法的调用,但用wraps=A时方法调用没被记录,用autospec=True又没法执行原始方法。
问题根源
当你用mock.patch('__main__.A', wraps=A)时,mock类m在被实例化时会调用原始的A.__init__,返回的是原始A的实例,而不是mock实例。这个原始实例的方法没有被mock包装,所以m.method_calls自然不会记录这些方法的调用。
而autospec=True会生成一个模仿原始类结构的mock,但默认情况下,这些mock方法不会调用原始实现,只会记录调用行为。
解决方案:包装实例并关联到类mock
我们可以自定义mock类的side_effect,让它在创建原始实例后,用一个mock包装这个实例。这样既会执行原始代码,又能跟踪实例方法的调用,同时这些调用会被关联到类mock的method_calls中。
下面是完整的实现代码:
import mock class A: def __init__(self, some_arg): print("constructor") def f(self, some_var): print(some_var) def spied_instance_creator(*args, **kwargs): # 创建原始类的实例,保证实际代码执行 original_instance = A(*args, **kwargs) # 用mock包装原始实例,跟踪方法调用 spied_instance = mock.Mock(wraps=original_instance, spec=A) return spied_instance # 打补丁,使用自定义的实例创建逻辑 patch = mock.patch('__main__.A', side_effect=spied_instance_creator) mocked_class = patch.start() # 执行你的业务代码 a = A('something') a.f('my_arg') # 验证实例化和方法调用都被跟踪 assert mock.call('something') in mocked_class.mock_calls # 注意:实例方法调用在类mock的method_calls中会以call().f(...)的形式存在 assert mock.call().f('my_arg') in mocked_class.method_calls # 结束补丁(可选,在测试框架中通常会自动处理) patch.stop()
为什么这样有效?
spied_instance_creator函数负责创建原始实例,确保__init__和f的实际代码被执行。- 用
mock.Mock(wraps=original_instance, spec=A)包装原始实例,既保留了原始方法的功能,又能跟踪所有方法调用。 - 类mock的
side_effect返回这个包装后的实例,所以实例的方法调用会被记录到类mock的method_calls中。
这样你就能同时满足“运行实际代码”和“监视实例化、方法调用”两个需求了。
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

