我在文件main.py
中定义了类MyClass
,如下所示:
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
在文件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
三种测试方法之间的差异通过代码和代码中的注释来解释。
哪一个是最佳实践,为什么?有更好的解决方案吗?
三种方法之间的主要区别
我认为这三种测试方法之间的主要区别是:
test_method_2_v1()
调用MyClass
的method_1()
test_method_2_v2()
和test_method_2_v3()
不调用MyClass
的method_1()
这意味着test_method_2_v1()
执行method_1()
的间接测试,而其他两种测试方法仅执行method_2()
的测试。
test_method_2_v2((和test_method _2_v3((之间的比较
在test_method_2_v2()
和test_method_2_v3()
之间,我认为最好的是test_method_2_v3()
,因为在可能的情况下,使用模拟对象通常是可取的,因为它有助于创建单元测试(模拟对象用于模拟精确test case
中对象的行为,而不是整个对象(。
单元测试是一种验证特定功能的测试。在这种情况下,test_method_2_v3()
验证method_2()
返回属性d
的值增加4
。
在我看来,test_method_2_v2()
做的事情太多了,所以它不是一个好的单元测试。
test_method_2_v2((如何成为单元测试
我认为最好修改test_method_2_v2()
,可能的代码如下:
def test_method_2_v2(self):
instance = MyClass()
instance.d = 3
# check that method_2 return 'd' increases of 4
assert instance.method_2() == 7
以前的代码在不使用mock对象的情况下变得类似于test_method_2_v3()
。现在test_method_2_v2()
只验证method_2()
的正确性(作为一个测试单元必须这样做(。