单元测试的概念
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,要根据实际情况去判定其具体含义。一个单元可能是功能模块、类、方法(函数)等。
单元测试工具
不同的编程语言都有比较成熟的单元测试框架,语法规则有些差别,其核心思想都是相通的。常见的单
元测试框架有:
Java语言:Junit、TestNG
Python语言:UnitTest、Pytest
UnitTest单元测试框架
一、UnitTest框架介绍
UnitTest是Python自带的一个单元测试框架,用它来做单元测试。也经常应用到UI自动化测试和接口自
动化测试中,用来管理和维护测试用例脚本
使用UnitTest框架的好处:
1. 能够组织多个用例去执行(可以把多条测试用例封装成一个测试套件,实现批量执行测试用例)
2. 提供了丰富的断言方法,方便对用例执行的结果进行判断
3. 能够生成HTML格式的测试报告
4. 使用Fixture功能可以减少代码的冗余
UnitTest核心要素:
TestCaseTestSuiteTestRunnerTestLoader
二、TestCase
TestCase就是表示测试用例
案例
定义一个实现加法操作的函数,并对该函数进行测试
如何定义测试用例
1.导包:importunittest
2.定义测试类:新建测试类必须继承unittest.TestCase
3.定义测试方法:测试方法名称命名必须以test开头
示例代码:
#test01_add.py文件#需求:定义一个实现加法操作的函数,并对该函数进行测试#实现加法操作defadd(x,y):returnx+y#导包importunittest#定义测试类:必须要继承unittest.TestCaseclassTestAdd(unittest.TestCase):#定义测试方法,必须要以test开头deftest01_add(self):result=add(1,1)print("result1=",result)deftest02_add(self):result=add(0,0)print("result2=",result)if__name__=='__main__':unittest.main()
如何执行测试用例
方式一:使用pycharm在代码上点击鼠标右键,选择使用UnitTest运行
方式二:调用unittest.main()来运行
三、TestSuite
说明:(翻译:测试套件)多条测试用例集合在一起,就是一个TestSuite使用:
实例化:suite=unittest.TestSuite() (suite:为TestSuite实例化的名称)添加用例:suite.addTest(ClassName("MethodName"))(ClassName:为类名;MethodName:为方法名)添加扩展:suite.addTest(unittest.makeSuite(ClassName))(搜索指定ClassName内test开头的方法并添加到测试套件中)提示:TestSuite需要配合TestRunner才能被执行
四、TextTestRunner
说明:TextTestRunner是用来执行测试用例和测试套件的使用:
1.实例化:runner=unittest.TextTestRunner()
2.执行:runner.run(suite)#suite:为测试套件名称
示例代码:
#test02_sub.py文件importunittestclassTestSub(unittest.TestCase):deftest01_sub(self):print("test01_sub")#导包importunittestfromtest01_addimportTestAddfromtest02_subimportTestSub#实例化测试套件对象suite=unittest.TestSuite()添加测试用例suite.addTest(TestAdd("test01_add"))suite.addTest(TestAdd("test02_add"))suite.addTest(unittest.makeSuite(TestSub))#实例化运行器对象runner=unittest.TextTestRunner()#运行测试套件runner.run(suite)
五、Fixture
说明:Fixture是一个概述,对一个测试用例环境的初始化和销毁就是一个Fixture
Fixture控制级别:
方法级别使用:
1. 初始化 ( 前置处理 ):def setUp(self) --> 首先自动执行2. 销毁 ( 后置处理 ):def tearDown(self) --> 最后自动执行3. 运行于测试方法的始末,即:运行一次测试 方法就会运行一次 setUp 和 tearDown
类级别使用:
1. 初始化 ( 前置处理 ):@classmethoddef setUpClass(cls): --> 首先自动执行2. 销毁 ( 后置处理 ):@classmethoddef tearDownClass(cls): --> 最后自动执行3. 运行于测试类的始末,即:每个测试类只会 运行一次 setUpClass 和 tearDownClass
模块级别【了解】使用:
1. 初始化 ( 前置处理 ):def setUpModule() --> 首先自动执行2. 销毁 ( 后置处理 ):def tearDownModule() --> 最后自动执行3. 运行于整个模块的始末,即:整个模块只会 运行一次 setUpModule 和 tearDownModule
示例代码使用:
# 需求:在一个测试类中定义多个测试方法,查看每 个测试方法执行完所花费的时长。import time import unittest# 模块级别,初始化、前置def setUpModule (): print ("setUpModule" )# 模块级别,销毁、后置处理def tearDownModule (): print ("tearDownModule" )class TestFixture (unittest .TestCase ): # 类级别,初始化、前置处理 @classmethod def setUpClass (cls ): print ("setUpClass" )# 类级别,销毁、后置处理 @classmethod def tearDownClass (cls ): print ("tearDownClass" )# 初始化,前置处理def setUp (self ):print ("start time=" , time .time ())# 销毁,后置处理def tearDown (self ):print ("end time=" , time .time ())def test_01 (self ):print ("test_01" )def test_02 (self ):print ("test_02" )class TestFixture2 (unittest .TestCase ):def test0001 (self ):print ("TestFixture2.test0001" )
六、UnitTest 断言
什么是断言
概念:让程序代替人为判断测试程序执行结果是否符合预期结果的过程UnitTest 中提供了非常丰富的断言方法,但是常用的也就那么几个,并且使用起来也比较简单
使用方式:
断言方法经在unittest.TestCase 类中定义好了,而且我们自定义的测试类已经继承了 TestCase ,所以在测试方法中直接调用即可。
import unittestdef add (x, y):return x + yclass TestAssert (unittest .TestCase ):def test01 (self ):num = add (1, 2)self .assertEqual (3, num )def test02 (self ):num = add (1, 2)is_ok = num == 3self .assertTrue (is_ok )
七、UnitT est 参数化
通过参数的方式来传递数据,从而实现数据和脚本分离,也可以把测试数据定义到数据文件或者数据库中。针对同一个测试方法,可以实现用例的重复执行,减少代码冗余,提高测试效率。unittest测试框架,本身不支持参数化,但是可以通过安装 unittest 扩展插件rameterized 来实现。安装parameterized
pip install parameterized
parameterized 使用方式
导包:from par ameterized import par ameterized使用@par ameterized.e xpand 装饰器可以为测试函数的参数进行参数化 示例代码# 方式一@parameterized .expand ([( 1, 1, 2), ( 1, 0, 1), ( 0, 0, 0)]) def test_add (self , x, y, expect ): pass# 方式二data = [( 1, 1, 2), ( 1, 0, 1), ( 0, 0, 0)] @parameterized .expand (data ) def test_add (self , x, y, expect ): pass# 方式三def build_data (): return [( 1, 1, 2), ( 1, 0, 1), ( 0, 0, 0)] @parameterized .expand (build_data ) def test_add (self , x, y, expect ): pass
示例代码
import unittestfrom parameterized import parameterized# 求和def add (x, y):return x + y# 构建测试数据def build_data ():return [( 1, 1, 2), ( 1, 0, 1), ( 0, 0, 0)]class TestAdd (unittest .TestCase ):@parameterized .expand ([( 1, 1, 2), ( 1, 0, 1), ( 0, 0, 0)])def test_add_1 (self , x, y, expect ):print ("x={} y={} expect={}" .format (x, y, expect ))result = add (x, y)self .assertEqual (result , expect )data = [( 1, 1, 2), ( 1, 0, 1), ( 0, 0, 0)]@parameterized .expand (data )def test_add_2 (self , x, y, expect ):print ("x={} y={} expect={}" .format (x, y, expect ))result = add (x, y)self .assertEqual (result , expect )@parameterized .expand (build_data )def test_add_3 (self , x, y, expect ):print ("x={} y={} expect={}" .format (x, y, expect ))result = add (x, y)self .assertEqual (result , expect )
八、生成HTML 测试报告
测试脚本执行完后,可以生成以 HTML( 网页 ) 格式的测试报告
为什么要生成测试报告:
测试报告是本次测试结果的体现形态测试报告内包含了有关本次测试用例的详情使用HTML TestRunner 生成测试报告
使用方法:
1. 复制 HTMLTestRunner.py 文件到项目文件夹2. 导入 HTMLTestRunner 、 unittest 包 3. 生成测试套件suite = unittest.TestSuite() suite.addTest(TestAdd("test_01"))4. 设置报告生成路径和文件名 file_name = "./report/report.html"5. 打开报告 with open(file_name,'wb') a s f:6 . 实例化 HTMLTestRunner 对象: runner = HTMLTestRunner(stream=f,[title],[description])参数说明: stream :文件流,打开写入报告的名称及 写入编码格式 ) title : [ 可选参数 ] ,为报告标题 description : [ 可选参数 ] ,为报告描 述信息7. 执行: runner.run(suite)
示例代码:
# 导包import unittest from test01_add import TestAdd from tools .HTMLTestRunner import HTMLTestRunner# 创建测试套件suite = unittest .TestSuite () suite .addTest (unittest .makeSuite (TestAdd ))# 定义测试报告存放路径report_path = "./report/report.html"# 打开文件流with open (report_path , "wb" ) as f: # 创建 HTMLTestRunner 运行器对象 runner = HTMLTestRunner (f, title ="xxx 测试报告 " , description ="V1.0..." )# 运行测试套件 runner .run (suite )