最近跟海洁一起用python的unittest测试框架+Django搭建了一个mock平台,关于单条接口的执行和报告生成的部分记录下自己的实现和学习理解。
unittest基本原理
简单介绍写下unittest,它是python的标准测试库,相比于其他测试框架是python目前使用最广的测试框架。
unittest有四个比较重要的概念是test fixture, test case, test suite, test runner, 。
test fixture:The test fixture is everything we need to have in place to exercise the sut。简单来说就是做一些测试过程中需要准备的东西。常用于初始化或清理测试环境,例如创建临时的数据库,文件和目录等,其中 setUp() 和
tearDown
() 是最常用的方法。
test case:用户自定义的测试case的基类,调用run()方法,会依次调用setUP()方法、执行用例的方法、tearDown
()
方法。
test suite:测试用例集合,可以通过addTest()方法手动增加Test Case,也可通过TestLoader自动添加Test Case,TestLoader在添加用例时,会没有顺序。
test runner:运行测试用例的驱动类,可以执行TestCase,也可执行TestSuite。执行后TestCase和Testsuite会自动管理TestResult。
通过dir(unittest),看到unittest全部的属性和方法,其中几个比较重要的类的关系如下图所示。
正常调用unittest的流程是,TestLoader 自动将测试用例TestCase中加载到TestSuite里,TextTestRunner调用TestSuite的run方法,顺序执行里面的TestCase中以test开头的方法,并得到测试结果TestResult。在执行TestCase过程中,先进行SetUp()环境准备,执行测试代码,最后tearDown()进行测试的还原。
其中TestLoader在加载过程中,进行添加的TestCase是没有顺序的。一个TestCase里如果存在多个验证方法的话,会按照方法中test后首字母的排序进行执行。
通过手动调用TestSuite的addTest、addTests方法来动态添加TestCase,既可确定添加用例的执行顺序,也可避免TestCase中的验证方法一定要用test开头。
在搭建接口测试平台的时候,每新建一个接口的时,会自动生成一个 TestCase,选中运行单个接口时,使用TextTestRunner直接调用单个TestCase。运行多个接口时,手动给TestSuite添加TestCase,供TextTestRunner调用并生成测试结果。
重写UnittestResult改变执行结果显示
在执行测试用例的过程中,通过设置verbosity(默认=1)的参数去执行测试用例。verbosity是指测试结果的显示粒度情况,默认为1时,成功输出.,失败输出 F。
在Unittest默认生成TestResult的过程中,生成的结果比较单一,所以测试平台重写了TestResult类,让其在执行测试用例中,可提供并记录更多的信息。
重写过程中,想增加的信息如下:
1、在TestCase执行中,记录控制台print的输出
2、每执行一个用例时,对成功的用例、失败的用例进行统计
下面简单举例下 对TestResult addSuccess()方法的重写实现:
#重写TestResult的addSuccess方法
def addSuccess(self, test):
#成功运行的总数+1
self.success_count += 1
#默认的TestResult的记录增加
TestResult.addSuccess(self, test)
#返回执行过程中的控制台输出
output = self.complete_output()
#重写返回结果,第一个参数0代表成功的用例执行情况(0成功,1失败,2错误),test代表执行的用例,output控制台输出结果,最后字符串代表错误信息
self.result.append((0, test, output, ''))
#记录控制台输出方法
def complete_output(self):
#初始化控制台
if self.stdout0:
sys.stdout = self.stdout0
sys.stderr = self.stderr0
self.stdout0 = None
self.stderr0 = None
#如果有上一次的记录位置,定位到上一次记录的位置并继续
self.outputBuffer.seek(self.last_location)
#从控制台输出流中读取数据并记录
output = self.outputBuffer.read()
#记录这一次的输出流位置
self.last_location += len(output)
return output
通过对TestResult 方法进行重写后,我们可获得到了单条接口的执行情况(0成功,1失败,2错误),当前执行的用例,控制台输出结果和错误信息。
测试平台单条用例的执行
作为最常用的单条接口执行结果的展示,我们最简单的是展示当前接口的返回信息、验证结果。
调用重写的TestReuslt,我们单条用例的返回结果test_result包含了:当前用例的运行结果(0成功,1失败)+当前TestCase+控制台输出(string)+错误信息(string)
# 返回单个接口运行结果
def run_single_test(inter):
g = GETestFactory()
interclass = g.create_test(inter)
test_suit = unittest.TestSuite()
test_suit.addTests(map(interclass, ["test_case"]))
runner = SingleTestRunner.SingleTestRunner()
test_result = runner.run(test_suit)
return test_result
单条用例的执行效果:
测试报告的生成
关于接口测试平台的测试报告,需要显示很多的信息,其中包括
1、测试报告名称、
2、执行通过、执行失败的总数
3、执行用例的名称、执行结果、执行情况
重写后的TestResult已经基本支持了这些情况。
具体的报告的页面实现逻辑就准备一个html页面模板,将每条用例执行的结果进行遍历,把结果填充到html页面中进行展示。
# 运行多个测试接口
def run_many_test(inters, title='接口自动化测试质量报告'):
g = GETestFactory()
test_suit = unittest.TestSuite()
for i in inters:
interclass = g.create_test(i)
test_suit.addTests(map(interclass, ["test_case"]))
run(test_suit, title)
print ("运行完成")
测试报告的页面最终实现效果:
本文来自网易实践者社区,经作者王紫琦授权发布。