unittest单元测试框架
unittest基本简介
unittest是Python自带的一个单元测试框架,unittest又被称为PyUnit,是由Java的JUnit衍生而来,基本结构是类似的。对于单元测试,需要设置预先条件,对比预期结果和实际结果。
由于unittest是Python自带的标准模块,所以不需要单独再去安装。引入包import unittest即可使用。
unittest基本概念
unittest核心的四个概念
test fixture:fixture表示test case运行前需要做的准备工作以及结束后的清理工作。比如,创建临时/代理数据库、目录或启动一个浏览器进程。
test case:test case是单元测试中的最小个体,通常是使用assert方法(断言)检查动作和输入的响应。unittest提供了一个基础类TestCase,一般是基于TestCase类进行扩充,来创建test case测试用例。
test suite:test suite(套件)是test case的合集,通常用test suite将test case按需求汇总后,统一执行。(批量执行用例)
test runner:test runner是一个执行器,用来执行测试用例或者套件。并将测试结果保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。并提供图形界面、文本界面或者返回一个值展示测试结果。
如何创建一个测试类
所有测试用例类都要继承TestCase
基本类
1、导入unittest
2、定义一个测试类class
,例如:class Test_demo(unittest.TestCase)
test fixture常用的四个方法
1、基于函数级别的方法
- setup(): 每个测试方法运行前执行一次
- teardown(): 每个测试方法运行完后执行一次
2、基于类级别的方法
- setUpClass(): 在测试类执行前执行一次
- tearDownClass(): 在测试类执行完后执行一次
unittest编写测试方法(用例)规范
- py文件需要以test开头。(规范,不必须)
- 测试类名称需要Test开头。(规范,不必须)
- 每个测试方法名称均以test开头,否则是不被unittest识别的。(规范,必须)
- 在unittest框架中,测试用例就是TestCase的实例,所以每个测试类必须继承unittest中TestCase类来编写用例。
- 测试方法必须带self参数,用来单独运行或则组合运行用例。
- 测试用例的执行顺序是按照测试方法名的ASCII编码字符集的顺序进行排序的。
执行测试脚本
- unittest.main():将一个单元测试模块变为可直接运行的测试脚本,main()方法是使用TestLoader类来搜索所有包含在该模块中以test命名开头的测试方法,并自动执行他们。
- 执行方法的默认顺序是:根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| """ 1.学习目标 掌握unittest框架下测试用例编写方法 2.操作步骤 2.1 导入unittest 2.2 创建测试类 测试类名称需要Test开头 继承unittest中的TestCase基本类 class Test_demo(unittest.TestCase): 2.3 编写test fixture setUp()--前置函数 tearDown()--后置函数 setUpClass()--+@classmethod tearDownClass()+@classmethod 2.4 编写test case 测试方法名称均以test开头 测试用例执行顺序:按照测试用例名称ASCII字符集编码排序。 所以我们在执行测试类中的测试方法的时候,要注意测试方法的执行顺序。 3.需求 编写简单的测试类 """
import unittest
class Test_demo(unittest.TestCase): def setUp(self) -> None: print("setUp在每个测试用例执行前先执行。") def tearDown(self) -> None: print("tearDown在每个测试用例执行后执行。") @classmethod def setUpClass(cls) -> None: print("setUpClass在测试类执行前先执行。") @classmethod def tearDownClass(cls) -> None: print("tearDownClass在测试类执行后执行。") def test_case_03(self): """测试用例3,这里是测试用例的备注""" print("执行测试用例3") def test_case_02(self): """测试用例2""" print("执行测试用例2") def test_case_01(self): """测试用例1""" print("执行测试用例1") if __name__ == '__main__': unittest.main() """ 输出结果: setUpClass在测试类执行前先执行。 setUp在每个测试用例执行前先执行。 执行测试用例1 tearDown在每个测试用例执行后执行。 setUp在每个测试用例执行前先执行。 执行测试用例2 tearDown在每个测试用例执行后执行。 setUp在每个测试用例执行前先执行。 执行测试用例3 tearDown在每个测试用例执行后执行。 tearDownClass在测试类执行后执行。 """
|
测试结果说明
测试执行完成后,会打印如下信息
1 2 3 4 5
| Ran 3 tests in 0.008s
OK
|
执行结果有如下三种
- OK :表示测试用例全部通过。
- F :表示测试用例没通过,代码没有问题。
- E :表示代码有问题。
断言方法
断言介绍
- 在执行测试用例的过程中,最终用例是否执行通过,是通过判断测试得到的实际结果和预期结果是否相等决定的,这时会用到断言方法。
- 本着没有消息就是最好的消息的原则,如果断言成功不采取任何措施(不输入任何日志),否则就会触发
AssertionError
(断言错误)的异常。
常用的断言方法
断言方法名称 |
使用参数 |
验证 |
assertEqual()(常用) |
a, b, [msg=’测试失败时打印的信息’] |
断言 a 和 b 是否相等,相等则测试用例通过 |
assertNotEqual() |
a, b, [msg=’测试失败时打印的信息’] |
断言 a 和 b 是否不相等,不相等则测试用例通过 |
assertTrue()(常用) |
x, [msg=’测试失败时打印的信息’] |
断言 x 是否为 True,是 True 则测试用例通过 |
assertFalse() |
x, [msg=’测试失败时打印的信息’] |
断言 x 是否为 False,是 False 则测试用例通过 |
assertIs() |
a, b, [msg=’测试失败时打印的信息’] |
断言 a 是否是 b,是则测试用例通过 |
assertNotIs() |
a, b, [msg=’测试失败时打印的信息’] |
断言 a 是否不是 b,不是则测试用例通过 |
assertIsNone() |
x, [msg=’测试失败时打印的信息’] |
断言 x 是否为 None,是 None 则测试用例通过 |
assertIsNotNone() |
x, [msg=’测试失败时打印的信息’] |
断言 x 是否不为 None,不是 None 则测试用例通过 |
assertIn() |
a, b, [msg=’测试失败时打印的信息’] |
断言 a 是否在 b 中,在 b 中则测试用例通过 |
assertNotIn() |
a, b, [msg=’测试失败时打印的信息’] |
断言 a 是否不在 b 中,不在 b 中则测试用例通过 |
assertIsInstance() |
a, b, [msg=’测试失败时打印的信息’] |
断言 a 是否是 b 的一个实例,是则测试用例通过 |
assertNotIsInstance() |
a, b, [msg=’测试失败时打印的信息’] |
断言 a 是否不是 b 的一个实例,不是则测试用例通过 |
提示:如果a和b断言失败,则输出msg中定义的信息,如果没有定义msg,则输出系统异常。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| """ 1.学习目标 必须掌握unittest中断言使用 2.语法 2.1 编写位置 在测试用例中去编写,先执行测试用例,最后一行断言。 2.2 使用的断言方法 注意:前边a是预期,后边b是测试实际的值 (1)assertEqual(a,b,msg) 断言a和b是否相等,如果相等,断言成功,否则断言失败 (2)assertTrue(x,msg) 断言条件x是否为True,如果是,断言成功,否则断言失败 (3)其他断言用法类似。 2.3 判定断言结果 断言成功,控制台没有任何提示 断言失败,控制台AssertionError关键字会出现 3.需求 编写一个有断言的测试类 """
import unittest
class Test_demo(unittest.TestCase): def test_case_03(self): """测试用例3""" print("执行测试用例3") self.assertEqual(2, 1 + 1, msg="断言成功") """ 执行结果: 断言成功,控制台没有任何提示 下面是总测试结果的日志: 执行测试用例3 # 在0.005秒内进行1次测试 Ran 1 test in 0.005s # 测试用例全部通过 OK """ def test_case_02(self): """测试用例2""" print("执行测试用例2") self.assertEqual(3, 1 + 1, msg="断言失败") """ 执行结果: 执行测试用例2 断言失败 3 != 2 Expected(预期) :2 Actual(实际) :3 下面会有报错信息(主要内容): AssertionError: 2 != 3 : 断言失败 # 在0.008秒内进行1次测试 Ran 1 test in 0.008s # 失败一个测试用例 FAILED (failures=1) # 断言失败 Assertion failed """ def test_case_01(self): """测试用例1""" print("执行测试用例1") self.assertTrue(1 > 2, msg="条件不成立,断言失败")
if __name__ == '__main__': unittest.main()
|
跳过测试
什么是跳过测试
当测试用例写完后,有些模块有改动时候,会影响到部分用例的执行,这个时候我们希望暂时跳过这些用例。或者前面某个功能运行失败了,后面的几个用例是依赖于这个功能的用例,如果第一步就失败了,后面的用例也就没必要去执行了,为了节省用例执行时间,可选择直接跳过测试。
常用的跳过测试方法和装饰器
当执行有想要跳过的测试,我们可以通过skip
、skipIf
、skipUnless
装饰器跳过某个测试方法或者测试类。
- @unittest.skip(reason):
skip(reason)装饰器,无条件跳过装饰的测试,并说明跳过测试的原因。
- @unittest.skipIf(reason):
skipIf(condition,reason)装饰器,条件为真时,跳过装饰的测试,并说明跳过测试的原因。
- @unittest.skipUnless(reason):
skipUnless(condition,reason)装饰器,条件为假时,跳过装饰的测试,并说明跳过测试的原因。
- @unittest.expectedFailure:
测试标记为失败。
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| """ 1.学习目标 了解unittest中跳过测试方法使用 2.语法 2.1 放置在需要跳过的测试用例之前 @跳过测试方法 测试用例 2.2 分类 @unittest.skip(跳过原因):表示无条件跳过执行 @unittest.skipIf(判断条件,跳过原因): 当判断条件为真时,跳过测试 @unittest.skipUnless(判断条件,跳过原因):当判断条件为假时,跳过测试 @unittest.expectedFailure: 直接将用例标记为失败 3.需求 编写测试类,使用跳过测试 """
import unittest
class Test_demo(unittest.TestCase): def test_case_01(self): """测试用例1""" print("执行测试用例1") @unittest.skip("无条件跳过") def test_case_02(self): """测试用例2""" print("执行测试用例2") @unittest.skipIf(True, "条件为真,跳过测试") def test_case_03(self): """测试用例3""" print("执行测试用例3") @unittest.skipIf(2 > 3, "条件为假,执行用例") def test_case_04(self): """测试用例4""" print("执行测试用例4") @unittest.skipUnless(False, "条件为假,跳过测试") def test_case_05(self): """测试用例5""" print("执行测试用例5") @unittest.skipUnless(True, "条件为真,执行用例") def test_case_06(self): """测试用例6""" print("执行测试用例6") @unittest.expectedFailure def test_case_07(self): """测试用例7""" print("执行测试用例7") def test_case_08(self): """测试用例8""" print("执行测试用例8") if __name__ == '__main__': unittest.main()
|
TestCase.skipTest()方法
用TestCase.skipTest()
方法跳过某个测试方法(了解)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import unittest
class TestDmeo(unittest.TestCase): def test_case_01(self): """测试用例1""" print("执行测试用例1") def test_case_02(self): """测试用例2""" self.skipTest('跳过用例test_case2') print("执行测试用例2") if __name__ == '__main__': unittest.main()
|
测试套件
测试套件的作用
在我们实际工作,使用unittest框架会有两个问题:
- 我们知道测试用例的执行顺序是根据测试用例名称顺序执行的,在不改变用例名称的情况下,我们怎么来控制用例执行的顺序。
- 一个测试文件,我们直接执行该文件即可,但如果有多个测试文件,怎么实现多个测试文件一起执行行。
要解决上面两个问题,我们就要用到测试套件TestSuite。
使用测试套件
1)入门用法
用法:
unittest.TestSuite()
:创建测试套件。
addTest()
和 addTests()
方法是将测试用例添加到测试套件中。
unittest.TextTestRunner()
:通过该类下面的 run()
方法来运行 suite
所组装的测试用例,suite
测试套件为 run()
方法参数。
例如: 将 test_Demo1
模块下的 TestDmeo
类下的 test_case_01
测试用例添加到测试套件中。
1 2 3 4 5 6 7 8 9 10
| suite = unittest.TestSuite()
suite.addTest(test_Demo.TestDmeo('test_case_01'))
runner = unittest.TextTestRunner() runner.run(suite)
|
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import unittest
class TestDmeo(unittest.TestCase): def test_case_01(self): """测试用例1""" print("执行测试用例1") def test_case_02(self): """测试用例2""" print("执行测试用例2") def test_case_03(self): """测试用例3""" print("执行测试用例3") if __name__ == '__main__': suite = unittest.TestSuite() suite.addTest(TestDmeo('test_case_02')) suite.addTest(TestDmeo('test_case_03')) suite.addTest(TestDmeo('test_case_01')) runner = unittest.TextTestRunner() runner.run(suite)
|
提示:向测试套件中添加测试用例的顺序,就是测试用例执行的顺序。(此时解决了第一个问题)
根据不同的条件加载测试用例(了解)
提示:这种方式很少用,了解一下即可。都用下面(3)的方式。
例如:将``test_demo2模块下的TestDmeo类下的test_case_01`测试用例添加到测试套件中。
测试用例名格式:文件名+类名+方法名,一级一级的
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import unittest
class TestDmeo(unittest.TestCase): def test_case_0001(self): """测试用例0001""" print("执行测试用例0001") def test_case_0002(self): """测试用例0002""" print("执行测试用例0002") def test_case_0003(self): """测试用例0003""" print("执行测试用例0003") if __name__ == '__main__': suite = unittest.TestSuite() """ # 2.1 loadTestsFromName # 提示: name参数是传入文件名,字符串格式 格式:模块名.测试类名.测试用例名 """ """ # 2.2 loadTestsFromNames 参数是一个列表,列表中的元素格式同上 """ """ # 2.3 loadTestsFromTestCase 参数一个测试类名 当前模块直接传如测试类名称即可 """ suite_1 = unittest.TestLoader().loadTestsFromTestCase(TestDmeo) suite.addTest(suite_1) runner = unittest.TextTestRunner() runner.run(suite)
|
常用方式
unittest.defaultTestLoader()
:通过该类下面的discover()
方法可自动根据测试目录test_dir
匹配查找测试用例文件,如test*.py
,并将查找到的测试用例组装到测试套件中。
示例: discover=unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py')
测试套件示例
- 创建
test_case
包用来存放测试用例。
- 以上面两个测试类做例子,把
test_demo1
和test_demo2
两个测试用例类文件放入test_case
包中。
- 编写调用用例脚本
run_case.py
文件执行多个测试用例。
说明:
test_demo1
和test_demo2
两个文件,就是上面的示例。
下面是run_case.py
文件内容,需求是同时执行test_demo1
和test_demo2
两个文件中的测试用例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| """ 1.学习目标 run_case.py必须会写 2.操作步骤 2.1 明确测试用例存放路径 2.2 将要执行的用例添加到测试套件中 2.3 执行测试套件中的用例 3.注意事项 1.run_case.py文件需要放置在项目根目录下 2.所有测试用例都写在test_caset文件夹中 3.编写用例的py文件需要以test开头 """
import unittest
case_path = "./test_case"
""" # 如果只添加一个文件,pattern就直接填写文件名 start_dir, 指定case目录 pattern='test*.py', 匹配文件规则,# 选择文件夹中的写test_开头的py文件 """ discover = unittest.defaultTestLoader.discover(case_path, pattern="test*.py")
runner = unittest.TextTestRunner() runner.run(discover)
|
参考:http://t.csdnimg.cn/kIqKf