You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试类实例方法是否被调用?(规避破坏性代码)

问题描述

我有如下代码:

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()

原理说明

  • 当你patchMyClass后,调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:34:50