?UnitTest 框架
- 概念:UnitTest 是 Python 自带的一个单元测试框架,用它来做单元测试。
优点:
- 能够组织多个用例去执行;
- 提供丰富的断言方法;
- 能够生成测试报告
UnitTest 核心要素
- UnitTest主要包含的内容 :TestCase(测试用例)丶TestSuite(测试套件,把多个TestCase集成到一个测试TestSuite)丶TestRunner(执行测试用例)丶TestLoader(自动从代码中加载多个测试用例TestCase)丶Fixture(UnitTest特性)
TestCase
使用步骤:
- 第一步:导入unittest模块
- 第二步:实现一个类,这个类必须继承自unittest.TestCase类
- 第三步:类中每个方法代表一个测试用例,方法名必须以test开头
import unittest # :导入unittest模块
# 定义一个实现加法操作的函数,对该函数进行测试。
def add_number(a, b):
return a + b
# 实现一个类,这个类必须继承自unittest.TestCase类
class test_add(unittest.TestCase):
# 类中每个方法代表一个测试用例,方法名必须以test开头
def test1(self):
print(add_number(13, 1))
def test2(self):
print(add_number(5, 4))
def test3(self):
print(add_number("a", 4))
如何同时运行多个
py
文件中的测试用例?
TestSuite
说明:
(
翻译:测试套件
)
多条测试用例集合在一起,就是一个
TestSuite
。
使用步骤:
import unittest
import addnumber_01
# 实例化unittest.TestSuite类的对象
suite = unittest.TestSuite()
# addTest(py文件名.类名("方法名"))
suite.addTest(addnumber_01.test_add("test1"))
suite.addTest(addnumber_01.test_add("test2"))
# 只是把测试用例添加到了测试套件中,并不是执行测试用例
用unittest.makeSuite一次导入一个类中的所有测试方法
import unittest
import testcase_01
suite = unittest.TestSuite()
# suite.addTest(testcase_01.my_test("test_001"))
# suite.addTest(testcase_01.my_test("test_002"))
# 只是把测试用例添加到了测试套件中,并不是执行测试用例
suite.addTest(unittest.makeSuite(testcase_01.my_test))
TextTestRunner
-
作用:
执行在
suite
中的测试用例
-
使用方法 :
import unittest
import addnumber_01
# 实例化unittest.TestSuite类的对象
suite = unittest.TestSuite()
# addTest(py文件名.类名("方法名"))
suite.addTest(addnumber_01.test_add("test1"))
suite.addTest(addnumber_01.test_add("test2"))
# 只是把测试用例添加到了测试套件中,并不是执行测试用例
runner = unittest.TextTestRunner() # 实例化TextTestRunner的对象
runner.run(suite) # 调用对象的run方法
TestLoader
- 用来加载 TestCase 到 TestSuite 中,即加载满足条件的测试用例,并把测试用例封装成测试套件。
- 使用 unittest.TestLoader,通过该类下面的 discover()方法自动搜索指定目录下指定开头的.py 文件,并将查找到的测试用例组装到测试套件;
自动搜索指定目录下指定开头的
.py
文件,并将查找到的测试用例组 装到测试套件;
- test_dir: 为指定的测试用例的目录;
- pattern:为查找的.py 文件的格式;
如果文件名默认为
'test*.py'
也可以使用 unittest.defaultTestLoader 代替 unittest.TestLoader()
代码示例
import unittest
# 定义一个实现加法操作的函数,对该函数进行测试。
def add_number(a, b):
return a + b
# 实现一个类,这个类必须继承自unittest.TestCase类
class test_add(unittest.TestCase):
# 类中每个方法代表一个测试用例,方法名必须以test开头
def test1(self):
print(add_number(13, 1))
def test2(self):
print(add_number(5, 4))
使用TestLoader执行测试用例
import unittest
# 用TestLoader对象的discover方法来自动查找py,自动加载py文件中的方法
# 第一个参数是从哪里找py文件,"."从当前目录开始查找py文件
# 第二个参数是指定py文件的文件名,可以用通配符
suite = unittest.TestLoader().discover("./", "test*.py")
runner = unittest.TextTestRunner()
runner.run(suite)
TestSuite 与 TestLoader 区别
- TestSuite 需要手动添加测试用例(可以添加测试类,也可以添加测试类中某 个测试方法)。当只是要执行py文件中多个测试用例中的几个,而不是全部执行那么适合用TestSuite的addTest加载指定的测试用例。
- TestLoader 搜索指定目录下指定开头.py 文件,并添加测试类中的所有的测试 方法,不能指定添加测试方法。当要执行所有的py文件中的所有的测试用例,那么适合使用TestLoader
小结
- 所有的TestCase最终都是用TextTestRunner来执行的
- TextTestRunner执行的是TestSuite
- 一个TestSuite中可以有多个TestCase
Fixture
一个测试用例环境的初始化和销毁就是一个 Fixture 。可以在测试用例执行执行之前自动调用指定的函数,在测试用例执行之后自动调用指定的函数。
控制级别
- 方法级:每个方法执行前和执行后都自动调用函数
- 类级:不管类中有多少方法,一个类执行前后都自动调用函数
- 模块级:不管一个模块(一个模块就是一个py文件)中有多少类,模块执行前后自动调用函数
方法级别详解
- 在TestCase,也就是测试用例所在的class中定义方法
- def setUp(self) 当测试用例执行前,自动被调用
- def tearDown(self) 当测试用例执行后,自动被调用
- 如果一个TestCase中有多个测试用例,那么setUp和tearDown就会被自动调用多次
import unittest
# 定义一个实现加法操作的函数,对该函数进行测试。
def add_number(a, b):
return a + b
# 实现一个类,这个类必须继承自unittest.TestCase类
class test_add(unittest.TestCase):
def setUp(self):
print("测试用例执行之前,执行")
# 类中每个方法代表一个测试用例,方法名必须以test开头
def test1(self):
print(add_number(13, 1))
def test2(self):
print(add_number(5, 4))
def tearDown(self):
print("测试用例执行之后,执行")
类级
- 不管类中有多少方法,一个类开始的时候自动调用函数,结束的之后自动调用函数
- 类级的fixture一定要是类方法
@classmethod def setUpClass(cls) 类开始时自动调用的方法@clasmethod def tearDownClass(cls) 类结束的时候自动调用的方法
import unittest
# 定义一个实现加法操作的函数,对该函数进行测试。
def add_number(a, b):
return a + b
# 实现一个类,这个类必须继承自unittest.TestCase类
class test_add(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("setUPClass 执行")
@classmethod
def tearDownClass(cls):
print("tearDownClass 执行")
def setUp(self):
print("测试用例执行之前,执行")
# 类中每个方法代表一个测试用例,方法名必须以test开头
def test1(self):
print(add_number(13, 1))
def test2(self):
print(add_number(5, 4))
def tearDown(self):
print("测试用例执行之后,执行")
模块级
- 不管py文件中有多少个类,以及类中有多少方法,只自动执行一次
- 函数 def setUpModule() 在py文件开始的时候自动调用
- 函数 def tearDownModule() 在py文件结束的时候自动调用
def setUpModule():
print("setUpModule自动调用了")
def tearDownModule():
print("tearDownModule自动调用了")
总结
- 必须继承 unittest.TestCase 类,setUp、tearDown 才是一个 Fixture;
- setUp,tearDown:如果一个类中有多个测试用例,每执行一个测试用例之 前会调用一次 setUp,之后会调用一次 tearDown;
- setUpClass,tearDownClass:如果一个类中有多个测试用例,执行所有测试 用例之前只会调用一次 setUpClass,之后只会调用一次 tearDownClass;
- setUpModule,tearDownModule:只在 import 导入这个模块时会调用一次
- setUpModule,模块使用完成之后会调用一次 tearDownModule;
- setUpXXX:一般做初始化工作;
- tearDownXXX:一般做结束工作;
断言
概念:让程序代替人为判断测试程序执行结果是否符合预期结果的过程。
为什么要学习断言?
自动化脚本在执行的时候一般都是无人值守状态,我们不知道执行结果是否 符合预期结果,所以我们需要让程序代替人为检测程序执行的结果是否符合预期结果,这就需要使用断言。
UnitTest
常用断言方法
使用方式
断言方法已经在 unittest.TestCase 类中定义好了,而且我们自定义的测试类已经继承了 TestCase,所以在测试方法中直接调用即可
assertEqual(参数1, 参数2)
- 如果参数1,参数2的值相等,断言成功,否则断言失败
- 两个参数,有一个存放实际结果,有一个存放预期结果
import unittest
# 定义一个实现加法操作的函数,对该函数进行测试。
def add_number(a, b):
return a + b
# 实现一个类,这个类必须继承自unittest.TestCase类
class test_add(unittest.TestCase):
# 类中每个方法代表一个测试用例,方法名必须以test开头
def test1(self):
number = add_number(13, 1)
self.assertEquals(14,number)
assertIn(参数1, 参数2)
import unittest
# 定义一个实现加法操作的函数,对该函数进行测试。
def add_number(a, b):
return a + b
# 实现一个类,这个类必须继承自unittest.TestCase类
class test_add(unittest.TestCase):
# 类中每个方法代表一个测试用例,方法名必须以test开头
def test1(self):
print(add_number(131, 1))
def test2(self):
print(add_number(534, 4))
参数化
一条测试数据定义一个测试函数,代码冗余度太高。多个测试用例代码相同,只是测试数据不同,预期结果不同,可以把多个测试用例通过参数化技术合并为一个测试用例。
参数化
通过参数化的方式来传递数据,从而实现数据和脚本分离。并且可以实现用 例的重复执行。unittest
测试框架,本身不支持参数化,但是可以通过安装
unittest 扩展插件 parameterized
来实现
- pip install parameterized
使用方式
- 导包:from parameterized import parameterized;
- 使用@parameterized.expand 装饰器可以为测试函数的参数进行参数化;
- ?expand()里面是一个列表
- ?列表里面放多个元组, 每个元组中的成员就代表调用方法使用的实参
- 列表中有几个元组,方法就会自动被调用几次
方式一:
import unittest
from parameterized import parameterized
def my_sum(a, b):
return a + b
class my_test1(unittest.TestCase):
# a是调用my_sum的第一个参数
# b是调用my_sum的第二个参数
# c是预期结果
@parameterized.expand([(1, 2, 3), (5, 6, 110), (-1, 3, 2)])
def test_001(self, a, b, c):
num1 = my_sum(a, b) # 定义变量num1得到my_sum函数的返回值
self.assertEqual(num1, c) # num1里存放的是实际结果,11是预期结果
# 实际结果与预期结果相符,代表测试用例测试通过
# 不相符代表测试用例测试失败
方式二
:
方式三
:
跳过
对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行.可以通过@unittest.skip跳过指定的方法或者函数
语法:
?示例
@unittest.skip
def test_002(self):
print("test002")
生成 HTML 测试报告
什么是
HTML
测试报告
- 说明:HTML 测试报告就是执行完测试用例后,以 HTML(网页)方式将执行结 果生成报告。
为什么要生成测试报告
- 测试报告是本次测试结果的体现形态;
- 测试报告内包含了有关本次测试用例的详情;
HTML
生成报告方式
- TextTestRunner (UnitTest 自带)不建议使用
- HTMLTestRunner(第三方模板);
生成 HTMLTestRunner 测试报告步骤:
- 复制 HTMLTestRunner.py 文件到项目文件夹;
- 导入 HTMLTestRunner、unittest 包;
- 生成测试套件 suite = unittest.TestLoader().discover("./", "test*.py") ;
- 以只写方式打开测试报告文件 f = open("test01.html", "wb") ;
- 实例化 HTMLTestRunner 对象: runner = HTMLTestRunner(stream=f, title=" 自动化测试报告", description="Chrome 浏览器")
- stream:open 函数打开的文件流;
- title:[可选参数],为报告标题;
- description:[可选参数],为报告描述信息;比如操作系统、浏览器等版本;
- 执行:runner.run(suite);
import unittest
from HTMLTestRunner import HTMLTestRunner
# 用TestLoader对象的discover方法来自动查找py,自动加载py文件中的方法
# 第一个参数是从哪里找py文件,"."从当前目录开始查找py文件
# 第二个参数是指定py文件的文件名,可以用通配符
suite = unittest.TestLoader().discover(".", "my*.py")
# runner = unittest.TextTestRunner()
file = open("test01.html", "wb") # 用wb代表用二进制写方式打开文件
# runner = unittest.TextTestRunner(stream=file, verbosity=2)
runner = HTMLTestRunner(stream=file, title="我的第一个html测试报告")
runner.run(suite)
file.close()
|