测试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
相关产品推荐
相关产品推荐

