19.unittest原理

可莉
• 阅读 802

单元测试
单元测试(unit testing)是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的
被测功能模块。

unittest运行原理

19.unittest原理

_TestCase:_一个TestCase的实例就是一个测试用例。什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。

_TestSuite:_而多个测试用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite。 TestLoader是用来加载TestCase到TestSuite中的,其中有几个loadTestsFrom__()方法,就是从各个地方寻找TestCase,创建它们的实例,然后add到TestSuite中,再返回一个TestSuite实例。

_TextTestRunner:_extTestRunner是来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法。测试的结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。

fixture:而对一个测试用例环境的搭建和销毁,是一个fixture。
一个class继承了unittest.TestCase,便是一个测试用例,但如果其中有多个以 test 开头的方法,那么每有一个这样的方法,在load的时候便会生成一个TestCase实例,如:一个class中有四个test_xxx方法,最后在load到suite中时也有四个测试用例。

在每一个测试用例中可以重写 以下函数
setUp()该测试用例执行前的设置工作、
tearDown()该测试用例执行后的清理工作、
setUpClass()所有测试用例前的设置工作、
tearDownClass()所有测试用例执行后的清洗工作

在每一个测试用例中可以通过skip,skipIf,skipUnless装饰器跳过某个测试函数,或者用TestCase.skipTest方法跳过测试函数。

_流程:_写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。

注意说明:

1、TestLoader加载TestCase到TestSuite可以通过TestSuite实例对象的addTest()和addTests()方法向suite中添加case或suite

2、在Runner执行时,默认将执行结果输出到控制台,我们可以设置其输出到文件,在文件中查看结果(你可能听说过HTMLTestRunner,是的,通过它可以将结果输出到HTML中,生成漂亮的报告,它跟TextTestRunner是一样的,从名字就能看出来,这个我们后面再说)。

3、在进行测试时可以传递verbosity参数,用以控制执行结果的输出,0 是简单报告、1 是一般报告、2 是详细报告。

案例
业务函数

这里我们随意写几个业务函数,表示我们将要进行测试的功能函数。将功能函数文件存储成mathfunc.py

def add(a, b):
return a+b

def minus(a, b):
return a-b

def multi(a, b):
return a*b

def divide(a, b):
return a/b

TestCase测试用例
我们通过测试用例用代码来实现每一个测试的详细过程和针对测试目标要测试的内容。同目录下创建test_mathfunc.py

import unittest
from mathfunc import *

class TestMathFunc(unittest.TestCase):

# TestCase基类方法,所有case执行之前自动执行
@classmethod
def setUpClass(cls):
print("这里是所有测试用例前的准备工作")

# TestCase基类方法,所有case执行之后自动执行
@classmethod
def tearDownClass(cls):
print("这里是所有测试用例后的清理工作")

# TestCase基类方法,每次执行case前自动执行
def setUp(self):
print("这里是一个测试用例前的准备工作")

# TestCase基类方法,每次执行case后自动执行
def tearDown(self):
print("这里是一个测试用例后的清理工作")

@unittest.skip("我想临时跳过这个测试用例.")
def test_add(self):
self.assertEqual(3, add(1, 2))
self.assertNotEqual(3, add(2, 2)) # 测试业务方法add

def test_minus(self):
self.skipTest('跳过这个测试用例')
self.assertEqual(1, minus(3, 2)) # 测试业务方法minus

def test_multi(self):
self.assertEqual(6, multi(2, 3)) # 测试业务方法multi

def test_divide(self):
self.assertEqual(2, divide(6, 3)) # 测试业务方法divide
self.assertEqual(2.5, divide(5, 2))

if __name__ == '__main__':
unittest.main(verbosity=2)

注意:

skip装饰器一共有三个 unittest.skip(reason)、unittest.skipIf(condition,reason)、unittest.skipUnless(condition,reason),skip无条件跳过,skipIf当condition为True时跳过,skipUnless当condition为False时跳过。

每个测试方法均以 test 开头,否则是不被unittest识别的。

其实每一个test开头的方法都会加载为独立的测试用例。

在unittest.main()中加 verbosity 参数可以控制输出的错误报告的详细程度,默认是 1,如果设为 0,则不输出每一用例的执行结果。如果参数为2则表示输出详细结果。

TestSuite测试组
TestSuite用来控制多个测试用例和多个测试文件之间的测试顺序。(这里的示例中的几个测试方法并没有一定关系,但之后你写的用例可能会有先后关系,需要先执行方法A,再执行方法B)

我们添加到TestSuite中的case是会按照添加的顺序执行的。

下面我们就来试下将测试用例加载到测试组中。进行测试并将测试结果输出。
下面的代码存储成

import unittest
from test_mathfunc import TestMathFunc
from HTMLTestRunner import HTMLTestRunner

if __name__ == '__main__':
suite = unittest.TestSuite()

tests = [TestMathFunc("test_add"), TestMathFunc("test_minus"), TestMathFunc("test_divide")] # 添加测试用例列表
suite.addTests(tests) # 将测试用例列表添加到测试组中
suite.addTest(TestMathFunc("test_multi")) # 直接用addTest方法添加单个TestCase
# 用addTests + TestLoader。不过用TestLoader的方法是无法对case进行排序的
# loadTestsFromName(),传入'模块名.TestCase名'
suite.addTests(unittest.TestLoader().loadTestsFromName('test_mathfunc.TestMathFunc'))
suite.addTests(unittest.TestLoader().loadTestsFromNames(['test_mathfunc.TestMathFunc'])) # loadTestsFromNames(),类似,传入列表

# loadTestsFromTestCase(),传入TestCase
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMathFunc))

# suite中也可以套suite

# 将测试结果输出到测试报告中
# with open('UnittestTextReport.txt', 'a') as f:
# runner = unittest.TextTestRunner(stream=f, verbosity=2)
# runner.run(suite)

# 将测试结果输出到测试报告html中
# with open('HTMLReport.html', 'w') as f:
# runner = HTMLTestRunner(stream=f,
# title='MathFunc Test Report',
# description='generated by HTMLTestRunner.',
# verbosity=2
# )
# runner.run(suite)

# 直接将结果输出到控制台
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)

测试报告
上面我们实现了将测试结果输出到功控制台、txt、html三种形式。其中html的输出需要加载HTMLTestRunner.py模块。下载地址:https://github.com/626626cdllp/Test/blob/master/python-unittest/HTMLTestRunner.py

三种输出结果只能选择一种,不能全部选择。

控制台输出:

19.unittest原理

txt输出:

 19.unittest原理

html输出:

19.unittest原理

总结一下:
unittest是Python自带的单元测试框架,我们可以用其来作为我们自动化测试框架的用例组织执行框架。
unittest的流程:写好TestCase,然后由TestLoader加载TestCase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。
一个class继承unittest.TestCase即是一个TestCase,其中以 test 开头的方法在load时被加载为一个真正的TestCase。
verbosity参数可以控制执行结果的输出,0 是简单报告、1 是一般报告、2 是详细报告。
可以通过addTest和addTests向suite中添加case或suite,可以用TestLoader的loadTestsFrom__()方法。
用 setUp()、tearDown()、setUpClass()以及 tearDownClass()可以在用例执行前布置环境,以及在用例执行后清理环境
我们可以通过skip,skipIf,skipUnless装饰器跳过某个case,或者用TestCase.skipTest方法。
参数中加stream,可以将报告输出到文件:可以用TextTestRunner输出txt报告,以及可以用HTMLTestRunner输出html报告。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java单元测试
Java单元测试1.概述java单元测试是最小的功能单元测试代码,单元测试就是针对单个java方法的测试。java程序的最小功能单元是方法。main方法进行测试的缺点:只能有一个main()方法,不能把测试代码分离出来无法打印出测试结果和期望结果.例如:expected:
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
OpenStack基础知识
针对以前学的内容的一个简单整理1、单元测试工具介绍unittest:是Python的标准库,提供了最基本的单元测试功能,包括单元测试运行器(简称runner)和单元测试框架。项目的单元测试代码的测试类可以继承unittest.TestCase类,那么这个类就能够被runner发现并且执行。同时,unittest.TestCase
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Wesley13 Wesley13
3年前
C#单元测试
什么叫单元测试(unittesting)?是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这