在测试时使用mock或创建带有变通方法的真实实例



我在文件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()调用MyClassmethod_1()
  • test_method_2_v2()test_method_2_v3()不调用MyClassmethod_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()的正确性(作为一个测试单元必须这样做(。

最新更新