目标:
1.掌握UnitTest框架的基本使用方法
2.掌握断言的使用方法
3.掌握如何实现参数化
4.掌握测试报告的生成
1.定义
(1)框架(framework):为解决一类事情的功能集合。(需要按照框架的规定(套路) 去书写代码)
(2)UnitTest框架:UnitTest是Python自带的一个单元测试框架,用它来做单元测试。
自带的框架(官方): 不需要单外安装, 只要安装了 Python,就可以使用random, json, os, time 第三方框架: 想要使用 需要先安装后使用(pytest)selenium , appium, requests 单元测试框架: 主要用来做单元测试, 一般单元测试是开发做的. 对于测试来说, unittest 框架的作用是自动化脚本(用例代码) 执行框架(使用unittest框架 来管理运行多个测试用例的)
2.UnitTest核心要素
1.TestCase(测试用例)-》核心 每个 TestCase(测试用例) 都是一个代码文件 2.TestSuite(测试套件) 用来管理组装(打包)多个 TestCase(测试用例) 的 3.TestRunner(测试执行,测试运行) 用来执行TestSuite(测试套件)的 4.TestLoader(测试加载) 对 TestSuite(测试套件) 功能的补充, 5.Fixture(测试夹具) 书写在 TestCase(测试用例) 代码中, 是一个代码结构, 可以在每个方法执行前后都会执行的内容
1.TestCase(测试用例)代码文件书写
步骤: 1. 导包 (unittest) 2. 自定义测试类 3. 在测试类中书写测试方法 4. 执行用例 # 1.导包 import unittest # 2.自定义测试类 (需要继承unittest模块中的TestCase类) class TestDome(unittest.TestCase):# 3.书写测试方法 即:用例代码(目前没有真正的用例代码,使用print代替)#书写要求,测试方法必须以test_开头def test_method1(self):print('测试方法1') def test_method2(self):print('测试方法2') # 4.执行用例 # 1 将光标放在 类名的后边 运行, 会执行类中的所有的测试方法 # 2 将光标放在 方法名的后边 运行, 只执行当前的方法
2.TestSuite(测试套件) & TestRunner(测试执行)代码书写
步骤: 1. 导包(unittest) 2. 实例化(创建对象)套件对象 3. 使用套件对象添加用例方法 4. 实例化运行对象 5. 使用运行对象去执行套件对象 # 1.导包(unittest) import unittest #后面添加用例方法的时候导的包 from testcase1 import TestDome1 from testcase2 import TestDome2 # 2.实例化(创建对象)套件对象 suite = unittest.TestSuite() # 3. 使用套件对象添加用例方法 # 方式一, 套件对象.addTest(测试类名('方法名')) # 建议测试类名和方法名直接去复制,不要手写 suite.addTest(TestDome1('test_method1')) suite.addTest(TestDome1('test_method2')) suite.addTest(TestDome2('test_method1')) suite.addTest(TestDome2('test_method2')) # 4. 实例化运行对象 runner = unittest.TextTestRunner() # 5. 使用运行对象去执行套件对象 # 运行对象.run(套件对象) runner.run(suite)
3.TestLoader(测试加载)
步骤: 1. 导包 2. 实例化测试加载对象并添加用例 ---> 得到的是 suite 对象 3. 实例化 运行对象 4. 运行对象执行套件对象 # 1.导包 import unittest # 2.实例化加载对象并添加使用 # unittest.TestLoader().discover('用例所在路径','用例代码文件名') # 用例代码路径:推荐使用相对路径;用例代码文件名:可使用*通配符 suite = unittest.TestLoader().discover('./case','test*.py') # 3, 实例化运行对象 # runner = unittest.TextTestRunner() # # 4, 执行 # runner.run(suite) # 可以将 3 4 步 变为一步 unittest.TextTestRunner().run(suite)
4.Fixture(测试工具)
对一个测试用例环境的初始化和销毁就是一个Fixture Fixture控制级别: 1.方法级别(掌握) 2.类级别(掌握) 3.模块级别(了解) 1.方法级别:在每个测试方法(用例代码) 执行前后都会自动调用的结构 # 方法执行之前 def setUp(self):每个测试方法执行之前都会执行pass # 方法执行之后 def tearDown(self):每个测试方法执行之后都会执行pass 2.类级别:在每个测试类中所有方法执行前后 都会自动调用的结构(在整个类中 执行之前执行之后个一次) # 类级别的Fixture 方法, 是一个 类方法 # 类中所有方法之前 @classmethod def setUpClass(cls):pass # 类中所有方法之后 @classmethod def tearDownClass(cls):pass 3.模块级别:代码文件,在每个代码文件执行前后执行的代码结构 # 模块级别的需要写在类的外边直接定义函数即可 # 代码文件之前 def setUpModule():pass # 代码文件之后 def tearDownModule():pass
3.UnitTest断言
1.定义:
断言:让程序代替人工自动的判断预期结果和实际结果是否相符。
断言的结果有两种: True, 用例通过 ; False, 代码抛出异常, 用例不通过 在 unittest 中使用断言, 都需要通过 self.断言方法来试验
3.断言常用方法:
assertEqual:
self.assertEqual(预期结果, 实际结果) # 判断预期结果和实际结果是否相等 1. 如果相等, 用例通过 2. 如果不相等,用例不通过, 抛出异常
assertIn:
self.assertIn(预期结果, 实际结果) # 判断预期结果是否包含在实际结果中 1. 包含 ,用例通过 2. 不包含, 用例不通过, 抛出异常 assertIn('admin', 'admin') # 包含 assertIn('admin', 'adminnnnnnnn') # 包含 assertIn('admin', 'aaaaaadmin') # 包含 assertIn('admin', 'aaaaaadminnnnnnn') # 包含 assertIn('admin', 'addddddmin') # 不是包含
4.参数化
通过参数的方式来传递数据,从而实现数据和脚本分离,并且可以实现用例的重复执行。 unittest测试框架,本身不支持参数化,但是可以通过安装unittest扩展插件parameterized来实现 工作中场景: 1. 测试数据一般放在 json 文件中 2. 使用代码读取 json 文件,提取我们想要的数据 ---> [(), ()] or [[], []] cmd窗口安装或者在pycharm的终端安装 安装插件:pip install parameterized (pip 是 Python 中包(插件) 的管理工具, 使用这个工具下载安装插件) 验证:pip list # 查看到 parameterized 新建一个 python 代码文件, 导包验证:from pa... import pa... 参数化代码书写 步骤: 1. 导包 unittest/ pa 2. 定义测试类 3. 书写测试方法(用到的测试数据使用变量代替) 4. 组织测试数据并传参
例子2: data.json文件内容如下: [{"desc": "正确的用户名和密码","username": "admin","password": "123456","expect": "登录成功"},{"desc": "错误的的用户名","username": "root","password": "123456","expect": "登录失败"},{"desc": "错误的的密码","username": "admin","password": "123123","expect": "登录失败"} ] # 1. 导包 unittest/ pa import json import unittest from parameterized import parameterized from tools import login # 组织测试数据 [(), (), ()] or [[], [], []] def build_data():with open('data.json', encoding='utf-8') as f:result = json.load(f) # [{}, {}, {}]data = []for i in result: # i {}data.append((i.get('username'),i.get('password'),i.get('expect')))return data # 2. 定义测试类 class TestLogin(unittest.TestCase):# 3. 书写测试方法(用到的测试数据使用变量代替)@parameterized.expand(build_data())def test_login(self, username, password, expect):self.assertEqual(expect, login(username, password)) # 4. 组织测试数据并传参(装饰器 @)
5.跳过
对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行
使用方式: # 直接将测试函数标记成跳过 @unittest.skip('跳过额原因') # 根据条件判断测试函数是否跳过 , 判断条件成立, 跳过 @unittest.skipIf(判断条件, '跳过原因') 示例代码: import unittest # version = 30 version = 29 class TestDemo(unittest.TestCase):@unittest.skip('没有什么原因,就是不想执行')def test_1(self):print('测试方法 1')@unittest.skipIf(version >= 30, '版本大于等于 30, 不用测试')def test_2(self):print('测试方法 2')def test_3(self):print('测试方法3')
6.测试报告
自带的测试报告 只有单独运行 TestCase 的代码,才会生成测试报告
生成第三方的测试报告 1. 获取第三方的 测试运行类模块 , 将其放在代码的目录中 2. 导包 unittest 3. 使用 套件对象, 加载对象 去添加用例方法 4. 实例化 第三方的运行对象 并运行 套件对象 # 1. 获取第三方的 测试运行类模块 , 将其放在代码的目录中 # 2. 导包 unittest import unittest from HTMLTestRunner import HTMLTestRunner # 3. 使用 套件对象, 加载对象 去添加用例方法 suite = unittest.defaultTestLoader.discover('.', 'pa1.py') # 4. 实例化 第三方的运行对象 并运行 套件对象 # HTMLTestRunner() #pa1.py涉及的参数如下 # stream=sys.stdout, 必填,测试报告的文件对象(open ), 注意点,要使用 wb 打开 # verbosity=1, 可选, 报告的详细程度,默认 1 简略, 2 详细 # title=None, 可选, 测试报告的标题 # description=None 可选, 描述信息, Python 的版本, pycharm 版本 # file = 'report.html' # 报告的后缀是.html file = 'report1.html' # 报告的后缀是.html with open(file, 'wb') as f:# runner = HTMLTestRunner(f) # 运行对象runner = HTMLTestRunner(f, 2, '测试报告', 'python 3.6.8 ') # 运行对象#运行对象执行套件, 要写在 with 的缩进中runner.run(suite)1. 组织用例文件(TestCase 里边), 书写参数化, 书写断言, 书写 Fixture, 书写 跳过, 如果单个测试测试文 件, 直接运行, 得到测试报告, 如果有多个测试文件, 需要组装运行生成测试报告 2. 使用 套件对象组装, 或者使用 加载对象组装 3. 运行对象 运行 3.1 运行对象 = 第三方的运行类(文件对象(打开文件需要使用 wb 方式)) 3.2 运行对象.run(套件对象) import unittest from HTMLTestRunnerCN import HTMLTestReportCN # 组装用例方法 suite = unittest.defaultTestLoader.discover('.', '*pa1.py') # 实例化运行对象 with open('report_cn.html', 'wb') as f:runner = HTMLTestReportCN(f)runner.run(suite)
要有一个第三方的类库:HTMLTestRunner:用来执行测试用例并生成HTML格式的测试报告