隔离测试是相对与于整合测试来说的,现代软件架构流行分层式、模块化,而隔离测试就是相当于在每层上进行测试,整合测试就是跨越多个层进行测试
introduction #
举个简单例子来说,在django系列中,我们把表单提交分成两个层,一个form
层,一个式model
层
form
层相当于接近用户交互层,而model
层与数据库联系更大, form
层负责获取用户数据并验证,而model
层根据form
层数据将数据存入数据库。
隔离测试就是隔离form
层向model
层提交,而整合测试就是直接测试form
层和model
层。
判断一个测试是整合测试还是隔离测试就是看测试的边界,整合测试相当于我们更加熟悉,我们测试时通过伪造form提交,然后通过数据库获取存入数据来得到验证,而隔离测试就比较复杂,因为我们很难在一个耦合度高代码找到怎么隔离两个层的方法。
接下来我就介绍python里一个神器:mock
自己用过其他语言框架中的mock,但是python里面mock里面最神奇的的是里面的patch
,就像一个超级补丁一样。
Example #
接下来我用一个例子来介绍一下如何写隔离测试
首先我们在 lists.forms.py
中一个表单model
class ListForm(forms.models.ModelForm):
def save(self):
pass
我们在lists.models.py
有个model
class List(models.Model):
def create_now():
pass
现在来分析一下这个隔离测试,我们要测试ListForm
中save
方法
首先ListForm
和List
两个类是耦合的,一个整合测试,我们只要调用save
方法,然后查询数据库就可以完成这个测试,然而隔离测试不同,我们只能测试在调用save
方法时,他“干”了什么。他可能调用了List
的create_now
方法,将得到表单数据传了过去。
意味着我们只能测试到save
方法调用了List
方法。
那这个隔离单元测试该怎么写?
接下来我们隆重介绍mock里面的最强补丁patch
根据TDD原则,我们先新建一个单元测试IsolutionFormTest
import unittest
from unittest.mock import patch, Mock ##load super patch
from lists.models import List
from lists.forms import ListForm
class IsolutionFormTest(unitest.TestCase):
@patch('lists.forms.List.create_new')
def test_save_creates_new_list(self, mock_list_create_new):
form = ListForm(data={'text': "example text"})
form.is_valid() # get clean data
form.save()
mock_list_create_new.assert_called_once_with(
text= "example text"
) # the major test
我来介绍一下这个patch
,就像名字一样补丁,通过我们使用字符串将要替换的函数写出来,当test
运行时,会自动将函数替换成一个mock
对象,通过参数(上面的mock_list_create_new
)赋给函数。
你可以这样想象,当form.save()
调用时,在save
函数里面,我们如果使用了lists.forms.List.create_new
这个函数,这个函数就会被直接被补丁替换掉,你如果使用了lists.forms.List.create_new(text="xxx")
就会变成mock_list_create_new(text="xxx")
,当你调用了mock_list_create_new(text="xxx")
时,mock_list_create_new
这个mock
对象就会记录下来。
这样我们就通过mock_list_create_new
测试了函数是否执行了没有,因为隔离开form
层和model
层的就是通过两者之间的接口。我们只用测试接口是否执行了没有就可以了。
这样我们就完成了隔离单元测试,运行一下肯定失败,我们接下来就把save
方法完善一下通过测试。
from django import form
form list.models import List
class ListForm(forms.models.ModelForm):
def save(self):
List.create_new(text=self.cleaned_data['text'])
ok测试通过了,我们就可以歇一口气了。
Conclusion #
相对于整合测试,隔离测试运行速度更快,但是相对的隔离测试对接口要求非常严格,好的方面利用我们进行更好的代码设计,更好的分析代码的复杂程度,并且当接口变迁的时候,隔离测试能迅速发现变化而报警,然而隔离测试工作量比较大,而且没有整合测试那么好理解。在实际生产中对于复杂的接口我们尽量进行隔离测试,对于简单接口我们使用整合测试能根据减少程序的耦合性,而且能迅速发现集成问题。
ps:对patch
感兴趣的童鞋可以自行google,patch
好玩的地方还有很多,这里为了篇幅我只介绍了最核心的使用方法,大家可以自行探索patch
更多好玩的东西。s