如何测试类实例方法是否被调用?(规避破坏性代码)
问题描述
我有如下代码:
class MyClass: def __init__(self, value=1): self.value = value self.destructive_stuff() def destructive_stuff(self): print("Running destructive commands on the host...") def compute_value(self): return self.value * 10 def main(): sample = MyClass(value=5) print(f"Computed value: {sample.compute_value()}") if __name__ == "__main__": main()
我想测试main()函数,核心是检查compute_value()方法是否被调用。因为不想初始化MyClass的真实实例(会执行destructive_stuff()),所以用Mock来测试:
import unittest from unittest.mock import patch import my_sample class TestPieq(unittest.TestCase): @patch("my_sample.MyClass") def test_called(self, mock_myclass): my_sample.main() mock_myclass.compute_value.assert_called()
但运行测试失败了:
$ python3 -m unittest tests.py Computed value: <MagicMock name='MyClass().compute_value()' id='140298914799936'> F ====================================================================== FAIL: test_called (tests.TestSample) ---------------------------------------------------------------------- Traceback (most recent call last): File "/usr/lib/python3.10/unittest/mock.py", line 1379, in patched return func(*newargs, **newkeywargs) File "/tmp/pieq/tests.py", line 9, in test_called mock_myclass.compute_value.assert_called() File "/usr/lib/python3.10/unittest/mock.py", line 898, in assert_called raise AssertionError(msg) AssertionError: Expected 'compute_value' to have been called. ---------------------------------------------------------------------- Ran 1 test in 0.002s FAILED (failures=1)
如果直接patchMyClass.compute_value,测试能通过,但会触发真实类的初始化,执行destructive_stuff():
class TestSample(unittest.TestCase): @patch("my_sample.MyClass.compute_value") def test_called(self, mock_myclass_compute): my_sample.main() mock_myclass_compute.assert_called()
运行结果:
$ python3 -m unittest tests.py Running destructive commands on the host... Computed value: <MagicMock name='compute_value()' id='140289139827584'> . ---------------------------------------------------------------------- Ran 1 test in 0.001s OK
请问怎么才能既避免执行destructive_stuff(),又能正确验证compute_value()被调用?
解决方案
错误原因
你之前的测试写法有误:mock_myclass是类的Mock对象,而compute_value()是实例方法,是被MyClass的实例调用的,不是类本身。所以你应该检查的是mock_myclass返回的实例(也就是MyClass()创建的对象)上的compute_value是否被调用。
正确测试代码
修改测试代码,通过mock_myclass.return_value获取类实例的Mock对象,然后验证该实例的compute_value方法:
import unittest from unittest.mock import patch import my_sample class TestSample(unittest.TestCase): @patch("my_sample.MyClass") def test_called(self, mock_myclass): # 获取MyClass实例的Mock对象 mock_instance = mock_myclass.return_value my_sample.main() # 验证实例的compute_value被调用 mock_instance.compute_value.assert_called()
原理说明
- 当你patch
MyClass后,调用MyClass(value=5)时,实际上返回的是mock_myclass.return_value这个MagicMock对象。 sample.compute_value()调用的是这个实例Mock上的方法,所以要检查mock_instance.compute_value的调用情况,而不是类Mock本身的compute_value。- 这种写法完全不会初始化真实的
MyClass,自然也就不会执行destructive_stuff()。
运行这个测试,结果会是:
$ python3 -m unittest tests.py Computed value: <MagicMock name='MyClass().compute_value()' id='xxxxxx'> . ---------------------------------------------------------------------- Ran 1 test in 0.001s OK
既不会触发破坏性操作,又能正确验证方法调用。
内容的提问来源于stack exchange,提问作者Pierre
相关产品推荐
相关产品推荐

