python单元测试框架unittest
unittest中最核心的四个概念是:test case, test suite, test runner, test fixture。
下面我们分别来解释这四个概念的意思,先来看一张unittest的静态类图(下面的类图以及解释均来源于网络)
1.一个TestCase的实例就是一个实例。什么是测试用例呢?就是一个完整的测试流程,包括测试前环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(teardown)。单元测试(unit test)的本质也就在这里,一个测试用例是一个完整的测试单元,通过运行这个测试单元,可以对某一个问题进行验证。
2.而多个测试用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite。
3.TestLoader是用来加载TestCase到TestSuite中的,其中有几个LoaderTestsFrom__()方法,就是从各个地方寻找TestCase,创建他们的实例,然后add到TestSuite中,在返回一个TestSuite实例。
4.TextTestRunner是用来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法。测试的结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息
5.而对一个测试用例环境的搭建和销毁,就是一个fixture
一个class类继承了unittest.TestCase,便是一个测试用例,但如果其中有多个以test开头的方法,那么每有一个这样的方法,在load的时候便会生成一个TestCase实例,如:一个class中有四个test_xxx方法,最后在load到suite时也会有四个测试用例
到这里流程就清晰了:
写好TestCase,然后由TestLoader加载Testcase到TestSuite,然后由TextTestRunner来运行TestSuite,运行的结果保存在TextTestResult中,我们通过命令行或者unittest.main()执行时,main会调用TextTestRunner中的run来执行,或者我们可以直接通过TextTestRunner来执行用例。这里加个说明,在Runner执行时,默认将执行结果打印在控制台,我们可以设置其输出到文件,在文件中查看结果(你可能听说过HTMLTestRunner,是的,通过它可以将结果输出到HTML中,生成漂亮的报告,它跟TextTestRunner是一样的,从名字就能看出来。)
unittest实例
下面我们通过一些实例来更好的认识一下unittest。
先准备待测方法:
mathfunc.py
简单示例:
接下来我们为这四个方法写测试
test_mathfunc.py
执行结果:
能够看到一共运行了4个测试,失败了1个,并且给出了失败原因,2.5!= 4 也就是说我们的divide方法是有问题的。
这就是一个简单的测试,有几点需要说明:
1.从上面可以看出,测试的执行跟方法的顺序没有关系,test_devide写在的第四个,但是却是从第2个开始执行的
2.每个测试方法均以test开头,否则是不被unittest识别的。
3.在unittest.main()中加verbosity参数可以控制输出的错误报告的详细程度,默认是1,如果设置为0,则不输出每一用例的执行结果,如果设置为2,则输出详细的执行结果
组织TestSuite
上面的代码示例了如何编写一个简单的测试,但有两个问题,我们怎么控制用例执行的顺序呢?(这里的示例中的几个方法并没有一定关系,但之后你的写用例可能会有先后关系,需要先执行方法A,再执行方法B),我们就要用到TestSuite了。我们添加到TestSuite中的case就会按照添加的顺序去执行
问题二是我们现在只写了一个测试文件,我们直接执行该文件即可,但如果有多个测试文件,怎么进行组织,总不能一个个的执行文件吧,答案也在TestSuite中。
再举个栗子:
在文件夹中我们再新建一个文件test_suite.py
可以看到执行结果,执行了三个case,并且顺序是按照我们添加进suite的顺序执行的。
这里我们用到的是TestSuite的addTests()方法,并直接传入了TestCase列表,我们还可以
1.直接用addTest添加单个TestCase
2.用addTests + TestLoader,loadTestsFromName()/loadTestsFromNames(),传入类名.文件名(模块名.TestCase名)
3.使用loadTestsFromTestCase(),传入类名(TestCase名)
注意,用TestLoader的方法是无法对case进行排序的,同事,suite中可以嵌套suite。
将结果输出到文件中
用例组织好了,但结果只能输出到控制台,这样是没有办法查看之前的执行记录,我们想将结果输出到文件。很简单,看示例
执行此文件,可以看到,在同目录下生成了UnittestTextReport.txt文件,所有的执行报告均输出到了此文件中,我们便有了txt格式的测试报告了
test fixture之setUp() tearDown()
上面整个测试基本跑了下来,但可能会遇到点特殊的情况:如果我的测试需要在每次执行之前准备环境,或者在每次执行之后需要进行一些清理怎么办?比如执行前需要连接数据库,执行完成之后需要还原数据库,断开连接。总不能每个测试方法中都添加准备环境、清理环境的代码吧。
这就涉及到我们之前说过的test fixture了,修改test_mathfunc.py:
我们添加了setUp()和teatDown()两个方法(其实是重写了TestCase的这两个方法),这两个方法在每个测试方法执行前以及执行后执行一次,setUp用来为测试准备环境,teatDown用来清理环境,以备之后的测试。
执行后如下:
可以看到setUp和tearDown在每次执行case前后都执行了一次。
如果想要在所有case执行之前准备一次环境,并在所有case执行结束之后再清理环境,我们可以用setUpClass()与tearDownClass()
执行结果如下:
可以看到setUpClass一级tearDownClass均只执行了一次。
跳过某个case
如果我们临时想要跳过某个case不执行怎么办?unittest也提供了几种方法:
1.skip装饰器
执行后结果:
可以看到总的test数量还是4个,但divide()方法被skip了
skip装饰器一共有三个unittest.skip(reason)、unittest.skipIf(condition, reason)、unittest.skipUnless(condition, reason),skip无条件跳过,skipIf当condition为True时跳过,skipUnless当condition为False时跳过。
1.TestCase.skipTest()方法
执行后结果:
执行test_suite.py
执行test_mathfunc.py
效果跟上面的装饰器一样,跳过了divide方法
进阶--用HTMLTestRunner输出漂亮的HTML报告
我们能够输出txt格式的文本执行报告了,但是文本报告太过简陋,我们可以借助外部第三方库来生成好看直观的HTML报告。
HTMLTestRunner是一个第三方的unittest HTML报告库,首先我们下载HTMLTestRuner.py,并放到当前目录下,或者python安装目录下的lib下,就可以导入使用。
查看报告: