1. 单元测试介绍
1.1 常用的单元测试框架
*** Unittest**
Unittest测试框架,结构比较单一,测试报告也比较简单,是python内置的标准类库,不常用,了解即可;
*** Pytest**
Pytest测试框架,是丰富、灵活的测试框架,语法简单,可以结合allure生成多种样式的测试报告,比较常用;
*** Nose**
Nose测试框架,是对unittest的扩展,不常用;
*** Mock**
Mock测试框架是用来测试python的库,不常用;
1.2 单元测试类型
依据代码覆盖率的不同,单元测试类型分为4种:
- 语句覆盖
- 条件覆盖
- 判断覆盖
- 路径覆盖
样例:
被测代码片段
def demo_method(a,b,x):
if(a>1 and b==0):
x=x/a
if(a==2 or x>1):
x=x+1 return x
1)语句覆盖
通过设计一定量的测试用例,保证被测试的方法每一行代码都会被执行;
测试用例:
a=3,b=0,x=4,即可实现语句覆盖;
2)判断覆盖
通过设计测试用例,保证测试条件的所有真假情况都会被执行;
测试用例:
3)语句覆盖
通过设计测试用例,保证所有条件的真假都被覆盖;
测试用例:
被测试片段包含4个条件,覆盖所有条件的真假,需要设计16个测试用例;
4)路径覆盖
通过设计测试用例,覆盖所有可能执行的路径
2.unittest框架介绍
2.1 官网
https://docs.python.org/3/library/unittest.html
2.2 特点
- unittest是python自带的单元测试框架,常用于单元测试;
- unittest测试框架提供丰富的断言方法和验证函数等功能;
- unittest测试框架,结合HTMLTestRunner,可以生成html报告;
2.3 组成
- test fixture:测试准备
- test case:测试用例
- test suit:测试组件
- test runner:测试执行
2.4 样例
#导入unittest模块
import unittest
#定义类TestStringMethods,继承于unittest.TestCase
class TestStringMethods(unittest.TestCase):
#定义测试用例方法,必须以test开头,否则不会执行
def test_upper(self):
#断言
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
#定义主方法,调用全部的用例
if __name__ == '__main__':
unittest.main()
2.5 unittest编码规范
- 测试模块必须导入unittest模块
- 测试类必须继承unittest.TestCase类
- 测试方法必须以"test"开头
2.6 测试框架结构
1)setUp
在所有测试用例执行之前执行该方法;
2)tearDown
在所有测试用例执行之后执行该方法;
3)setUpClass
在类所有用例之前执行该方法;setUpClass为类方法,需要添加装饰器@classmethod;每个类执行1次;
4)tearDownClass之后执行
在类所有用例之后执行;tearDownClass为类方法,需要添加装饰器@classmethod;每个类执行1次;
2.7 unittest断言
常用断言
assertEqual(value1,value2,“判断value1是否等于value2”),说明:value1=value2,用例通过
assertNotEqual(value1,value2,“判断value1是否不等于value2”),说明:value!=value2,用例通过
self.assertEqual(1,2,"判断1是否等于2") #用例执行不通过
self.assertNotEqual(1,2,"判断1是否不等于2") #用例执行通过
2.8 测试用例运行方式
方式1:
执行所有的用例
unittest.main()方法调用
方式2:
执行指定的测试用例,通过测试组件TestSuit组装测试用例,然后通过TestRunner调用;
suite=unittest.TestSuit() #创建测试组件
suite.addTest(TestClass01("test_01")) #添加TestClass01类下的test_01用例到组件中
suite.addTest(TestClass02("test_02")) #添加TestClass02类下的test_02用例到组件中
unittest.TextTestRunner().run(suite) #执行测试组件,即执行TestClass01类下的test_01用例和TestClass02类下的test_02用例
方式3:
执行某个类或多个类的测试用例;通过TestLoader加载测试类,然后执行测试组件;
#加载测试组件
suite1 = unittest.TestLoader().loadTestsFromTestCase(TestClass01)
suite2 = unittest.TestLoader().loadTestsFromTestCase(TestClass02)
suite = unittest.TestSuite([suite2])
#执行测试组件
unittest.TextTestRunner(verbosity=2).run(suite)
方式4:
执行某个目录下符合指定规则的文件的所有测试用例;通过discover指定执行脚本的目录和规则,然后通过TextTestRunner执行脚本;
# 指定测试目录
test_dir = "./testcase01"
# 指定调用脚本的规则
discover = unittest.defaultTestLoader.discover(test_dir, pattern="test*.py")
#执行测试用例
unittest.TextTestRunner(verbosity=2).run(discover)
2.8 结合HTMLTESTRunner生成带日志的测试报告
HTMLTESTRunner源地址
https://github.com/huilansame/HTMLTestRunner_PY3
引用HTMLTestRunner_PY3.py下的HTMLTestRunner方法执行用例并生成报告
#设置测试报告标题
report_title = 'unittest测试报告'
desc = '用于展示修改样式后的HTMLTestRunner'
#指定测试报告的目录
report_file = './report/unittestReport.html'
# 指定测试目录
test_dir = "./testcase01"
# 指定执行脚本的规则
discover = unittest.defaultTestLoader.discover(test_dir, pattern="test*.py")
#执行用例并生成报告
with open(report_file, 'wb') as report:
runner = HTMLTestRunner(stream=report, title=report_title, description=desc)
runner.run(discover)
测试报告: