作者:Gakki
什么是单元测试?单元测试是指对软件中的最小可测试单元在与程序其他部分相隔离的情况下进行检查和验证的工作。这里的最小可测试单元通常是指函数或者类,一般是开发来做的。按照测试阶段来分,就是单元测试、集成测试、系统测试以及验收测试。
Unittest框架 (原名PyUnit框架)为Python语言自带的单元测试框架。
01 Unittest 四大组件
- test case:测试用例,方法命名基于 test_ 开头,默认根据ASCII码的顺序加载测试用例,排序规则: 0-9,A-Z,a-z。
- test fixture:测试夹具,设置前置条件( setup )和 后置条件 ( teardown ),每个测试用例方法执行前后都要执行这两个方法。
- test suite:测试套件,批量执行用例集。我们可以使用 TestLoader 来加载测试用例到测试套件中。
- test runner:运行器,用来执行测试用例的,并返回测试用例的执行结果。它还可以用图形或者文本接口,把返回的测试结果更形象的展现出来,如:HTMLTestRunner。
02 Unittest 的断言
- Unittest框架中也提供了一些自带的断言方式。
- 断言主要分为:
- 基本布尔型断言
- 比较断言
- 复杂断言
基本的布尔型断言:
- 注:结果只有 True 和 False
断言方法 | 断言方法 |
---|---|
assertEqual(arg1, arg2, msg=None) | 验证arg1=arg2,不等则fail |
assertNotEqual(arg1, arg2, msg=None) | 验证arg1 != arg2, 相等则fail |
assertTrue(expr, msg=None) | 验证expr是true,如果为false,则fail |
assertFalse(expr,msg=None) | 验证expr是false,如果为true,则fail |
assertIsNone(expr, msg=None) | 验证expr是None,不是则fail |
assertIsNotNone(expr, msg=None) | 验证expr不是None,是则fail |
assertIn(arg1, arg2, msg=None) | 验证arg1是arg2的子串,不是则fail |
- 注:如果断言失败即不通过就会抛出一个AssertionError断言错误,成功则标识为通过。msg参数默认是None,即msg = None,如果指定msg参数的值,则将该信息作为失败的错误信息返回。
03 Unittest.skip()装饰器
当运行用例时,有些用例可能不想执行等,可用装饰器暂时屏蔽该条测试用例。
- skip():无条件跳过
@unittest.skip(" skip this case ")
- skipIf(condition,reason):如果condition为true,则 skip
@unittest.skipIf(condition,reason)
- skipUnless(condition,reason):如果condition为False,则skip
@unittest.skipUnless(condition,reason)
04 编写用例步骤
编写测试用例前,我们需要建一个测试类继承unittest里面的TestCase类,继承这个类之后我们才是真正的使用unittest框架去写测试用例,编写测试用例的步骤如下:
- 导入unittest模块
- 创建一个测试类,并继承unittest.TestCase()
- 定义测试方法,方法名必须以test_开头
- 调用unittest.main()方法来运行测试用例,unittest.main()方法会搜索该模块下所有以test开头的测试用例方法,并自动执行
05 TestFixure 测试夹具
unittest的测试夹具有两种使用方式,一种是以测试方法为维度的setUp()和tearDown(),一种是以测试类为维度的setUpClass()和tearDownClass()。
06 TestSuite 测试套件
unittest.TestSuite()类来表示一个测试用例集,把需要执行的用例类或模块存到一起,常用的方法如下:
- unittest.TestSuite():
- addTest():添加单个测试用例方法
- addTest([..]):添加多个测试用例方法,方法名存在一个列表
- unittest.TestLoader():
- loadTestsFromTestCase(测试类名):添加一个测试类
- loadTestsFromModule(模块名):添加一个模块
- discover(测试用例的所在目录):指定目录去加载,会自动寻找这个目录下所有符合命名规则的测试用例
实例:
# 第一步,创建一个测试套件
suite = unittest.TestSuite()
# 第二步:将测试用例,加载到测试套件中
# 方式1,添加单条测试用例
case = test_register.TestRegister("test_register_success")
# 创建一个用例对象,注意:通过用例类去创建测试用例对象的时候,需要传入用例的方法名(字符串类型)
suite.addTest(case) # 添加用例到测试套件中
# 方式2,添加多条测试用例
case1 = test_register.TestRegister("test_register_success")
case2 = test_register.TestRegister("test_username_isnull")
suite.addTest([case1, case2]) # 添加用例到测试套件中
# 方式3,添加一个测试用例类
loader = unittest.TestLoader() # 创建一个加载对象
suite.addTest(loader.loadTestsFromTestCase(test_register.TestRegister))
# 方式4,添加一个模块
loader = unittest.TestLoader() # 创建一个加载对象
suite.addTest(loader.loadTestsFromModule(test_register))
# 方式5,指定测试用例的所在的目录路径,进行加载
loader = unittest.TestLoader()
suite.addTest(loader.discover(r"d:\learn\python"))
07 TestRunner 执行用例
test runner顾名思义就是用来执行测试用例的,并且可以生成相应的测试报告。测试报告有两种展示形式,一种是text文本,一种是html格式。
# 创建测试套件
suite = unittest.TestSuite()
# 通过模块加载测试用例
loader = unittest.TestLoader()
suite.addTest(loader.loadTestsFromModule(test_register))
# 创建测试运行程序启动器
runner = HTMLTestRunner(stream=open("report.html", "wb"), # 打开一个报告文件,将句柄传给stream
tester="Gakki", # 报告中显示的测试人员
description="登录接口测试报告", # 报告中显示的描述信息
title="自动化测试报告") # 报告的标题
# 使用启动器去执行测试套件里的用例
runner.run(suite)
参数说明:
- stream:指定输出的方式
- tester:报告中要显示的测试人员的名字
- description:报告中要显示的面熟信息
- title:测试报告的标题
- verbosity :表示测试报告信息的详细程度,一共三个值,默认是2
- 0 (静默模式):你只能获得总的测试用例数和总的结果,如:总共100个 失败10 成功90
- 1 (默认模式):类似静默模式,只是在每个成功的用例前面有个. 每个失败的用例前面有个F
- 2 (详细模式):测试结果会显示每个测试用例的所有相关的信息
08 杂谈
- 断言资料
基本布尔型断言
断言方法 | 断言方法 |
---|---|
assertEqual(arg1, arg2, msg=None) | 验证arg1=arg2,不等则fail |
assertNotEqual(arg1, arg2, msg=None) | 验证arg1 != arg2, 相等则fail |
assertTrue(expr, msg=None) | 验证expr是true,如果为false,则fail |
assertFalse(expr,msg=None) | 验证expr是false,如果为true,则fail |
assertIs(arg1, arg2, msg=None) | 验证arg1、arg2是同一个对象,不是则fail |
assertIsNot(arg1, arg2, msg=None) | 验证arg1、arg2不是同一个对象,是则fail |
assertIsNone(expr, msg=None) | 验证expr是None,不是则fail |
assertIsNotNone(expr, msg=None) | 验证expr不是None,是则fail |
assertIn(arg1, arg2, msg=None) | 验证arg1是arg2的子串,不是则fail |
assertNotIn(arg1, arg2, msg=None) | 验证arg1不是arg2的子串,是则fail |
assertIsInstance(obj, cls, msg=None) | 验证obj是cls的实例,不是则fail |
assertNotIsInstance(obj, cls, msg=None) | 验证obj不是cls的实例,是则fail |
比较断言
断言方法 | 断言方法 |
---|---|
assertAlmostEqual (first, second, places = 7, msg = None, delta = None) | 验证first约等于second。 palces: 指定精确到小数点后多少位,默认为7 |
assertNotAlmostEqual (first, second, places, msg, delta) | 验证first不约等于second。 palces: 指定精确到小数点后多少位,默认为7 注: 在上述的两个函数中,如果delta指定了值,则first和second之间的差值必须≤delta |
assertGreater (first, second, msg = None) | 验证first > second,否则fail |
assertGreaterEqual (first, second, msg = None) | 验证first ≥ second,否则fail |
assertLess (first, second, msg = None) | 验证first < second,否则fail |
assertLessEqual (first, second, msg = None) | 验证first ≤ second,否则fail |
assertRegexpMatches (text, regexp, msg = None) | 验证正则表达式regexp搜索匹配的文本text。 regexp:通常使用re.search() |
assertNotRegexpMatches (text, regexp, msg = None) | 验证正则表达式regexp搜索不匹配的文本text。 regexp:通常使用re.search() 说明:两个参数进行比较(>、≥、<、≤、约等、不约等) |
复杂断言
断言方法 | 断言方法 |
---|---|
assertListEqual(list1, list2, msg = None) | 验证列表list1、list2相等,不等则fail,同时报错信息返回具体的不同的地方 |
assertTupleEqual (tuple1, tuple2, msg = None) | 验证元组tuple1、tuple2相等,不等则fail,同时报错信息返回具体的不同的地方 |
assertSetEqual (set1, set2, msg = None) | 验证集合set1、set2相等,不等则fail,同时报错信息返回具体的不同的地方 |
assertDictEqual (expected, actual, msg = None | 验证字典expected、actual相等,不等则fail,同时报错信息返回具体的不同的地方 |
网友评论