unittest简要解析
作者:互联网
一、unittest是什么?
unittest是python内置的单元测试框架,具备编写用例、组织用例、执行用例、输出报告等自动化框架的条件。
使用unittest前需要了解该框架的几个概念:
即TestCase、TestSuite、TestLoader、TestRunner、TestFixture等
1、TestCase
一个完整的测试单元,执行该测试单元可以完成对某一个问题的验证,是所有用例类的父类,用例类需继承它才可被 unittest 发现并执行,例:
1 import unittest 2 3 4 def compare(a, b): # 待测试方法 5 return a > b 6 7 8 def divide(a, b): # 待测试方法 9 return a / b 10 11 12 13 class TestA(unittest.TestCase): # 用例类需继承TestCase 14 15 def setUp(self) -> None: 16 print('用例执行前的处理') 17 18 def tearDown(self) -> None: 19 print('用例执行后的处理') 20 21 def test_1(self): # 测试用例 22 self.assertTrue(compare(10, 10)) 23 24 def test_2(self): # 测试用例 25 self.assertFalse(10, 0) 26 27 28 if __name__ == '__main__': 29 unittest.main() # 执行当前类的所有测试用例
2、TestSuite
测试套件,看作是多个用例的集合(容器),例:
1 def create_suite(): 2 suite = unittest.TestSuite() # 创建suite 3 suite.addTest(TestA("test_1")) # 往suite里添加用例 4 suite.addTest(TestA("test_2")) # 往suite里添加用例 5 6 return suite # 返回添加完用例的suite
如何执行这个容器下文介绍
3、TestLoader
测试加载,该类用来寻找 test case 并将其加载到 test suite 中,提供了以下几种方法寻找(发现)test case,如下:
unittest.TestLoader().loadTestsFromTestCase(testCaseClass)
testCaseClass: 必须是 TestCase 的子类或孙类
unittest.TestLoader().loadTestsFromModule(module, pattern)
model:TestCase(用例)所在模块
pattern:str 类型,发现用例的规则,默认发现 test 开头的用例
unittest.TestLoader().loadTestsFromName(name)
name:str 类型,格式要求为 "model.class.method"
unittest.TestLoader().loadTestsFromNames(names)
names:list 类型, 格式要求同上
unittest.TestLoader().discover(path_dir, pattern, top_level_dir)
path_dir:str 类型,TestCase 文件路径
pattern:同上
top_level_dir:str 类型,TestCase 的顶层目录,默认为 None
实际运用:
1 def create_suite(): 2 path = r'D:\pythonworkspace\unittest_exercise' 3 4 suite = unittest.TestSuite() # 创建suite 5 6 # 发现指定路径的用例, 并返回一个 testCaseClass 7 discover = unittest.defaultTestLoader.discover(path) # 等同于 discover = unittest.TestLoader().discover(path) 8 9 # 将 discover 中的用例循环添加到 suite 中 10 for testCases in discover: 11 for testCase in testCases: 12 suite.addTest(testCase) 13 14 return suite # 返回添加完用例的suite
4、TestRunner
测试执行器,执行 suite 中的用例,并将结果保存到 TextTestResult 实例中,例:
1 if __name__ == '__main__': # 执行当前类的所有测试用例 2 suite = unittest.TestSuite() 3 cases = unittest.TestLoader().loadTestsFromName("unittest_exercise.unit_exercise.TestA") 4 5 for case in cases: 6 suite.addTest(case) 7 8 runner = unittest.TextTestRunner() # 创建 runner 实例 9 runner.run(suite) # 执行 suite 中的用例
5、TestFixture
测试夹具,用于测试用例执行前后的位置,根据适用范围,分为以下级别:
方法级:
def setUp(self): -->会在每个测试用例方法前自动执行
def tearDown(self): -->会在每个测试用例方法后执行
例:
1 import unittest 2 3 4 def compare(a, b): # 待测试方法 5 return a > b 6 7 8 def divide(a, b): # 待测试方法 9 return a / b 10 11 12 class TestA(unittest.TestCase): 13 14 def setUp(self) -> None: 15 print('用例执行前的处理') 16 17 def tearDown(self) -> None: 18 print('用例执行后的处理') 19 20 def test_1(self): # 测试用例 21 self.assertTrue(compare(10, 10)) 22 23 def test_2(self): # 测试用例 24 self.assertFalse(divide(10, 0)) 25 26 27 if __name__ == '__main__': # 执行当前类的所有测试用例 28 unittest.main()
执行结果:可看到执行了两次,因为有两个测试用例
类级:
表示每个测试类只会执行一次 TestFixture 方法,例:
1 class TestA(unittest.TestCase): 2 3 @classmethod 4 def setUpClass(cls) -> None: 5 print('用例执行前的处理') 6 7 @classmethod 8 def tearDownClass(cls) -> None: 9 print('用例执行后的处理') 10 11 def test_1(self): # 测试用例 12 self.assertTrue(compare(10, 10)) 13 14 def test_2(self): # 测试用例 15 self.assertFalse(divide(10, 0))
执行后的结果:可见该测试类执行时,只执行一次TestFixture 方法
模块级:
def setUpModule()
def setUpModule()
和上述一样的用法,这里不再赘述
6、其他
(1)HTML版的测试报告
具体实现如下:(因 HTMLTestRunner 比较麻烦,这里采用的是 BeautifulReport )
① 先导入 BeautifulReport (BeautifulReport要先下载,不过也可以先写上如下代码,然后凭借 pycharm 下载即可)
1 from BeautifulReport import BeautifulReport
② result = BeautifulReport(createSuite()) # 创建测试套件容器 这里的 creatSuite() 返回的是 suite 实例
result.report(filename=now + 'GAD_smoke', description='GAD冒烟测试', report_dir=filename) # 生成测试报告
参数:
filename:生成报告的文件名
description:生成报告的注释
report_dir:生成报告的存储路径
(2)测试用例执行顺序:
默认按照 ASCII 码值排序
也可以写一个类继承 TestLoader 类,重写其中的排序方法,以达到排序的目的(没试过,记录一下,哈哈)
(3)断言
一种检查实际结果与期望结果关系的方式,常见的几种断言方式如下:
assertEqual(a, b) a=b 则返回 True
assertNotEqual(a, b) a=b 则返回 False
assertTrue(exp) 表达式为True 则返回 True
assertFalse(exp) 表达式为True 则返回 False
assertIs(a, b) a is b 则返回 True
assertIsNot(a, b) a is b 则返回 Fasle
......更多可以查看 TestCase 类的源码
(4)装饰器 skip、skipIf、skipUnless
skip 使用方式:在用例方法上使用以下装饰器
@unittest.skip(reason='') # 表示跳过该测试用例,reason:跳过原因 def test_1(self): # 测试用例 self.assertTrue(compare(10, 10))
skipIf :
@unittest.skipIf(condition='布尔表达式', reason='') # 表达式为 True 则跳过该用例 def test_1(self): # 测试用例 self.assertTrue(compare(10, 10))
skipUnless:
@unittest.skipUnless(condition='布尔表达式', reason='') # 表达式为 True 则执行该用例 def test_1(self): # 测试用例 self.assertTrue(compare(10, 10))
扩展:expectedFailure
@unittest.expectedFailure # 预期失败,即该用例执行失败时不会算作失败 def test_1(self): # 测试用例 self.assertTrue(compare(10, 10))
(5)参数驱动 ddt(亲测可行)
老规矩第一步先引入 ddt,
from ddt import file_data, ddt # file_data 接收外部 yaml 文件会用到
第二步,在测试类上使用 @ddt, 如:
@ddt class test_Login(unittest.TestCase):
第三步,在测试用例方法上使用 file_data,如:
1 @file_data(UniversalMethod.get_path() + 'data\\user_login.yaml') # 括号内是 yaml 文件的路径 2 def test_login(self, **kwargs): 3 print(kwargs) 4 error_text = self.login_page.login_GAD(kwargs['username'], kwargs['password']) # 接收 yaml 文件内的参数 5 self.assertFalse(error_text is not None, msg=error_text) # 如果错误信息存在,则登录失败,输出错误提示信息
yaml文件格式:
二、实例
实例可参见我另一篇文章,地址
各方收集加上自己的理解,若有不正之处,欢迎指出
标签:10,简要,unittest,用例,suite,解析,self,def 来源: https://www.cnblogs.com/cicadaLuo/p/16424161.html