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

测试MyClass的method_2:三种方案孰为最佳实践?是否存在更优解?

单元测试最佳实践分析:MyClass的三种测试方案对比

1. 生产代码(main.py)

class MyClass:
    def __init__(self, a=1, b=2, c=3):
        self.a = a
        self.b = b
        self.c = c
    
        self.d = None
        self.e = None
        self.f = None
    
    def method_1(self):
        return self.a + self.b
    
    def method_2(self):
        return self.d + 4
    
    def method_3(self):
        return self.e + 10
    
    def run(self):
        self.d = self.method_1()
        self.e = self.method_2()
        self.f = self.method_3()
        # a lot more stuff here that takes time

2. 测试代码(test_file.py)

import unittest
from unittest.mock import patch
    
from main import MyClass
    
class TestMyClass(unittest.TestCase):
    def test_method_2_v1(self):
        # This test creates a real instance, but the attribute d is created
        # manually in the test, while in the production code is created
        # by the method run()
        instance = MyClass()
        instance.d = instance.method_1()
        instance.e = instance.method_2()
        assert instance.e == 7
    
    def test_method_2_v2(self):
        # As in the version 1 this test creates a real instance and the attribute
        # d is created manually in the test, but  This case does not run method_1
        # and gives an explicit value to attribute d
        instance = MyClass()
        instance.d = 3
        instance.e = instance.method_2()
        assert instance.e == 7
    
    @patch('main.MyClass', spec=True)
    def test_method_2_v3(self, my_class_mock):
        # This test uses a mock and verify the correctness of method_2()
        # directly on the mock object 
        mock_instance = my_class_mock()
        mock_instance.configure_mock(d=3)
        assert MyClass.method_2(mock_instance) == 7

3. 问题

上述三种测试方法的差异已在代码及注释中说明。请问哪种方法属于单元测试最佳实践?原因是什么?是否存在更优的测试方案?


4. 分析与解答

最佳实践方案:test_method_2_v2

这是三个方案中最贴合单元测试核心原则的,原因如下:

  • 严格隔离被测单元:单元测试的核心目标是验证单个方法的逻辑正确性,test_method_2_v2直接给instance.d赋值,完全避开了method_1的依赖,只测试method_2的核心逻辑——接收d的值并返回d+4。
  • 故障定位清晰:如果测试失败,能直接确定是method_2的逻辑出了问题,不会因为method_1的bug导致测试失败,避免了故障混淆。
  • 测试高效稳定:不需要执行额外的方法逻辑,测试执行速度快,也不会因为method_1的修改而影响method_2的测试结果,稳定性更高。

其他方案的问题

  • test_method_2_v1:将method_1和method_2的逻辑绑定测试,本质上是集成测试而非单元测试。如果method_1出现bug,这个测试也会失败,无法精准定位问题;若method_1有复杂逻辑,还会拖慢测试速度。
  • test_method_2_v3:过度使用mock,完全没必要mock被测类本身。mock的正确场景是隔离外部依赖(比如数据库、第三方API),而不是被测单元。这种测试方式不仅冗余,而且测试的是method_2作为类方法的调用逻辑,和生产环境中实例方法的使用场景脱节,测试价值有限。

更优的测试方案

可以基于test_method_2_v2的思路,增加参数化测试,覆盖更多边界场景,让测试更全面:

import unittest
from parameterized import parameterized  # 需要先安装:pip install parameterized

from main import MyClass

class TestMyClass(unittest.TestCase):
    @parameterized.expand([
        (0, 4),
        (3, 7),
        (-2, 2),
        (100, 104),
        (float('nan'), float('nan'))  # 处理特殊值
    ])
    def test_method_2_parametrized(self, input_d, expected):
        instance = MyClass()
        instance.d = input_d
        self.assertEqual(instance.method_2(), expected)

另外,建议使用unittest框架自带的断言方法(如self.assertEqual)替代原生assert,这样测试失败时会输出更详细的错误信息,便于调试。


内容的提问来源于stack exchange,提问作者Arman Mojaver

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 06:05:23