前言:在接口/UI自动化中,unittest框架或多或少也听到过,流行的框架我们需要重点去学习及掌握,接下来就一起来学习下吧
1、TestCase:测试用例类,用来定义测试用例函数的
2、TestSuite:测试套件,用来收集测试用例的
3、TestRunner:测试用例运行类,用来执行测试用例的,以测试套件维度去执行
4、TestFixture:测试脚手架,前置条件,后置处理
1、TestCase:先定义测试用例类,在测试用例类中写测试方法
2、TestSuite:收集你要执行的测试用例类或者文件里面的测试方法,放到测试套件
3、TestRunner:将收集好的测试条件放到测试用例运行器去执行,并收集测试结果
4、TestFixture:做好前置条件和后置处理
1、导入模块:import unittest,继承TestCase类
2、定义一个测试用例类:类名称必须Test开头
3、定义测试方法:测试方法也必须是test开头,必须写在测试用例类里面
4、框架执行入口:unittest.main(),自动收集当前py文件的测试用例,然后执行
1、前置条件(如果没有可以不写):sql语句执行、数据库连接创建、工具类的实例化
2、测试步骤(业务逻辑):数据替换、数据驱动
3、测试结果断言:响应结果断言、数据库数据断言
4、后置处理(如果没有可以不写):数据清理、数据库连接关闭
自动化中什么是前置后置?
答:前置:sql语句执行、数据库连接创建、工具类的实例化
后置:数据清理、数据库连接关闭
a) 类级别(以类级别的运行)
- 一、类级别(以类级别的运行)
- 前置:测试用例执行之前执行一次(当前测试用例类) ——
- @classmethod
- def setUpClass(cls) -> None:(固定写法,必须加@classmethod,源码就是加了)
-
- 后置:测试用例执行之后执行一次(当前测试用例类)——
- @classmethod
- def tearDownClass(cls) -> None: (固定写法,必须加@classmethod,源码就是加了)
-
-
- 解释:
- 类级别的前后置就是,比如你的测试用例有3条,那就每一条用例都会去执行前后置,
- 执行顺序:前置,第一条用例,第二条用例,后置
a) 示例:类级别
- #例子:
-
- class Test_class_setup(unittest.TestCase): #前置后置都需要类继承unittest.TestCase
-
- @classmethod #类级别的前置 必须加@classmethod
- def setUpClass(cls) -> None:
- print("我是类级别的前置")
-
- @classmethod
- def tearDownClass(cls) -> None: #类级别的后置 必须加@classmethod 这里后置放哪里都可以 你也可以放到最后一条用例后面去。
- print("我是类级别的后置")
-
- def test_01(self):
- print("用例001")
-
- def test_02(self):
- print("用例002")
-
- def test_03(self):
- print("用例003")
-
-
-
- if __name__ == '__main__':
- unittest.main()
b) 函数级别(以函数级别的运行)
- 二、函数级别(以函数级别的运行)
- 前置:每个测试用例执行之前执行一次 —— def setUp(self) -> None: (固定写法)
- 后置:每个测试用例执行之后执行一次 —— def tearDown(self) -> None:(固定写法)
-
- 解释:
- 函数级别的前后置就是,比如你的测试用例有3条,那就每一条用例都会去执行前后置,
- 执行顺序:前置,第一条用例,后置;前置 ,第二条用例,后置
b) 示例:函数级别
- 例子:
-
-
- class Test_setp(unittest.TestCase): #前置后置都需要类继承unittest.TestCase
-
- def setUp(self) -> None:#这里-> None是表示前置是没有返回值的
- print("我是函数级别的前置")
-
- def test_01(self): #中间可以放测试用例
- print("我是测试用例01")
-
- def tearDown(self) -> None:#这里-> None是表示后置是没有返回值的
- print("我是函数级别的后置")
-
- if __name__ == '__main__':
- unittest.main()
1、用例执行按照Ascii码顺序:0-9
#打印对应字符的ascii码
print(ord("a")) #97
#将ascii转换为对应的字符
print(chr(102))
断言的特点:
1、unittest以程序运行过程中是否抛出异常来判断用例是否执行成功
2、如果断言失败程序会抛出异常,框架就会把这个用例标记为失败
3、只要你的程序中执行出现了其他异常,框架也会去捕获异常并将用例标记为失败
例:self.assertEqual(1,1) 断言是否相等
unitest常见断言:
- 常见断言(unitest独有,pytest没有):
-
- 1、assertEqual(a, b)
- # a == b
- '''self.assertEqual(1 + 1, 2)#实际结果、预期结果是否相等'''
-
-
- 2、assertNotEqual(a, b)
- # a != b
- '''self.assertNotEqual(1, 2)#实际结果、预期结果是否不相等'''
-
-
- 3、assertTrue(x)
- # bool(x) is True
- '''self.assertTrue([1,2,3])#任何为真的表达式 非0 非空 true'''
-
-
- 4、assertFalse(x)
- # bool(x) is False
- '''self.assertFalse(0)#任何为假的表达式 0 空 false'''
-
-
- 5、assertIs(a, b)
- # a is b
- '''self.assertIs(1,1)#is身份运算符,a 是和 b引用自同一个对象'''
-
-
- 6、assertIsNot(a, b)
- # a is not b
- '''self.assertIsNot(1,2)#is not身份运算符,a 和 b不是引用自同一个对象'''
-
-
- 7、assertIn(a, b)
- # a in b
- '''self.assertIn(1,[1,2,3])#in成员运算符,a是b中一员,a在b中'''
-
-
- 8、assertNotIn(a, b)
- # a not in b
- '''self.assertNotIn(2,[1,3,4])#in成员运算符,a不是b中一员,a不在b中'''
-
-
- 9、assertIsInstance(a, b)
- # isinstance(a, b)
- '''self.assertIsInstance(123,int)#isinstance判断一个对象是否属于某个类或类型'''
-
-
- 10、assertNotIsInstance(a, b)
- # not isinstance(a, b)
- '''self.assertNotIsInstance([1,2,3],dict)#not isinstance判断一个对象不是否属于某个类或类型'''
-
-
- 11、assertGreater(a, b)
- # a > b
- '''self.assertGreater(5,2)#Greater判断a是否大于b'''
-
-
- 12、assertGreaterEqual(a, b)
- # a >= b
- '''self.assertGreaterEqual(5,5)#GreaterEqual判断a是否大于等于b'''
-
-
- 13、assertLess(a, b)
- # a < b
- '''self.assertLess(1,4)#less判断a是否小于b'''
-
-
- 14、assertLessEqual(a, b)
- # a <= b
- self.assertLessEqual(2,2)#less判断a是否小于等于b
unitest断言示例:
- 例子:
-
- 测试用例中:
-
- def test_03(self):
- print("用例003")
- self.assertEqual(1+1,3)#实际结果、预期结果是否相等,如:1+1的值 是否 等于3——这里错了后,会报错,用例执行就会不通过
try...except 捕获到的异常一定要抛出来给框架,否则框架就会认为用例执行成功的
异常捕获示例:
- 2、手动抛异常:raise AssertionError(e)
-
-
- def test_03(self):
- try:
- time.sleep(1)
- self.assertEqual(1,2)
- print("测试用例03")
- except Exception as e:
- # print("错误原因:",e)
- raise AssertionError(e)
-
-
-
- def test_03(self):
- try:
- self.assertEqual(1,2)
- print("用例003")
- except Exception as e:
- raise AssertionError(e)
a) 测试用例维度【了解】
- 添加一个测试用例
- suite.addTest(TestDemo("test_04"))
-
- 添加多个测试用例
- tests = [TestDemo("test_04"),TestDemo("test_02")]
- suite.addTests(tests)
a) 示例:测试用例维度
- 添加单条用例:
-
- from day16.unnitest_demo1 import Test_class_setup #先导入测试用例
- import unittest#导入unitest库
- suite = unittest.TestSuite() #创建测试套件进行收集用例
- suite.addTest(Test_class_setup("test_01")) #添加测试用例到套件内,这里是测试用例为单位
- run_now = unittest.TextTestRunner() #创建执行器
- run_now.run(suite) #执行器中添加测试套件后 进行运行
-
-
-
-
- 添加多条用例:
-
- from day16.unnitest_demo1 import Test_class_setup #先导入测试用例
- import unittest#导入unitest库
- suite = unittest.TestSuite() #创建测试套件进行收集用例
-
- case = [Test_class_setup("test_01"),Test_class_setup("test_02")] #多条测试用例,用[]装起来也可以
- suite.addTests(case) # 多条用addTests
- run_now = unittest.TextTestRunner() #创建执行器
- run_now.run(suite) #执行器中添加测试套件后 进行运行
b) 测试类维度【了解】
添加某个测试类(类里面所有的测试用例都会被执行)
suite.addTest(unittest.makeSuite(TestDemo))
当只要执行py文件中多个测试用例中的几个,而不是全部执行时,那么使用testsuite的addtest方法加载指定的测试用例
当执行所有的py文件中的所有的测试用例时,那么使用TestLoader
b) 示例:测试类维度
- 添加测试类级别的用例:
-
- from day17.wjh_test import Test_wjh
- import unittest
-
- suite = unittest.TestSuite() #实施例套件
- test_case = unittest.TestLoader().loadTestsFromTestCase(Test_wjh)
- #用这个方法,Python3不能用unittest.makeSuite(TestDemo)
- #TestLoader:可以从指定目录查找指定的py文件中的所有测试用例,自动加载到TestSuite中
-
- suite.addTest(test_case)
- run1 = unittest.TextTestRunner()
- run1.run(suite)
c) 模块为维度【掌握】
start_dir:测试文件目录
pattern='test*.py':测试用例文件名称,默认以test开头的py文件
case_dir = os.path.dirname(__file__)
suite = unittest.defaultTestLoader.discover(start_dir=case_dir)#指定某个目录下的某一类py文件进行运行,且运行所有测试用例
c) 示例:模块为维度
- 添加测试模块(用例文件)维度的用例————重点重点重点:
-
-
- # 3、模块为维度【掌握】
- # start_dir:测试文件目录
- # pattern='test*.py':测试用例文件名称,默认以test开头的py文件
- # case_dir = os.path.dirname(__file__)
- # suite = unittest.defaultTestLoader.discover(start_dir=case_dir)
-
- import os
- from day17.wjh_test import Test_wjh #导入测试用例
- from day17.wjh_test import Test_wjh01#导入测试用例
- import unittest
-
- case_dir = os.path.dirname(__file__) #当前目录路径
- suite = unittest.defaultTestLoader.discover(start_dir=case_dir,pattern='wjh_start*.py')
- #start_dir是函数中的参数,指:start_dir
- #pattern是函数中的参数,指的:如(pattern='test*.py':测试用例文件名称,默认以test开头的py文件)
- #默认可以不加pattern的参数,如果不加。他就默认找目录中 test文件开头py文件中的测试用例执行
-
- run1 = unittest.TextTestRunner()#TextTestRunner执行的是TestSuite
- run1.run(suite)
c) TextTestRunner 和 TestRunner() 区别
TextTestRunner 和 TestRunner() 区别,因为这里很多人以为这两者都是unitest的执行器
TextTestRunner:是执行TestSuite,也就是测试套件的用例
TestRunner():执行生成测试报告
数据驱动
一、什么叫数据驱动?
1、业务流程是固定的,变化的是业务中的数据
2、使用场景:业务流程一样,只是请求数据不一样
准备工作:
安装ddt(unitest自带的ddt驱动方式)
pip install ddt
安装ddt(unittestreport第三库(木森大佬写的))
pip install unittestreport
a)unitest自带的ddt驱动方式
- unitest自带的ddt驱动方式——例子:
-
-
- import unittest
- from ddt import ddt,data #导入ddt和data
-
- test_cases = [{"api":"/api/login","user":"admin"},{"api":"/api/login","user":"test"}] #列表嵌套字典
-
- @ddt #语法糖,使用ddt装饰器
- class Test_login(unittest.TestCase):#同样需要继承unittest.TestCase
- @data(*test_cases) #这里@data()表示需要添加数据进去,@data(*test_cases) 之所以加*号,是因为要解包,test_cases是列表嵌套字典
- def test_01(self,data): #这里一定主要 需要把数据驱动的变量添加进来,比如这里的data
- print("驱动")
- print(data["api"])#这里随便插一句,所有运行时,鼠标光标放在类外面去,不然会报错,这是个大坑,unitest垃圾!
-
-
-
- if __name__ == '__main__':
- unittest.main()
b)unittestreport第三库(木森大佬写的)驱动方式
- unittestreport(森哥)三方库的数据驱动
-
- import unittest
- from unittestreport import ddt,list_data #list_data是这个库的专门名字,主要就是为了省去解包的步骤,下面我们有讲解
-
- test_cases = [{"api":"/api/login","user":"admin"},{"api":"/api/login","user":"test"}] #列表嵌套字典
-
- @ddt #语法糖,使用ddt装饰器
- class Test_login(unittest.TestCase):#同样需要继承unittest.TestCase
- @list_data(test_cases) #@list_data()表示需要添加数据进去,这里不需要再解包上面的数据,因为@list_data有解包动作
- def test_01(self,data): #这里一定主要 需要把数据驱动的变量添加进来,比如这里的data
- print("驱动")
- print(data["api"])#这里随便插一句,所有运行时,鼠标光标放在类外面去,不然会报错,这是个大坑,unitest垃圾!
-
-
-
- if __name__ == '__main__':
- unittest.main()
a) unitest自带测试报告——不推荐,丑,不好用
1、BeautifulReport(unitest官网自带的报告)
pip install BeautifulReport==0.1.3
b) unittestreport :木森自研(重点掌握)
unittestreport 使用文档unittestreport 使用文档unittestreport 使用文档:https://unittestreport.readthedocs.io/en/latest/doc8_thread/
安装unittestreport:pip install unittestreport
b) 示例:unittestreport
- 实例:
-
- import unittest
- from unittestreport import TestRunner#导入测试报告模块
-
- case_dir = os.path.dirname(__file__) #当前目录路径
- suite = unittest.defaultTestLoader.discover(start_dir=case_dir)#pattern='wjh_start*.py' #收集用例
-
- runner = TestRunner( #实例化测试报告模块,填写相关信息
- suite=suite,
- filename="my_report.html",
- report_dir="./reports",
- title='测试报告',
- tester='小阿卷',
- desc="接口自动化项目测试报告",
- templates=3
- )
- runner.run()
- runner.send_email(
- host="smtp.qq.com",
- port=465,
- user="123456@qq.com",
- password="123123",
- to_addrs=["123456@qq.com"]
- )