Contents
  1. 1. introduction
  2. 2. Example
  3. 3. Conclusion

隔离测试是相对与于整合测试来说的,现代软件架构流行分层式、模块化,而隔离测试就是相当于在每层上进行测试,整合测试就是跨越多个层进行测试

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

现在来分析一下这个隔离测试,我们要测试ListFormsave方法

首先ListFormList两个类是耦合的,一个整合测试,我们只要调用save方法,然后查询数据库就可以完成这个测试,然而隔离测试不同,我们只能测试在调用save方法时,他“干”了什么。他可能调用了Listcreate_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

Contents
  1. 1. introduction
  2. 2. Example
  3. 3. Conclusion