UnitTest框架

目标:

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格式的测试报告

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/151670.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++ 获取当前时间(精确至秒、毫秒和微妙)

头文件 #include <chrono>三个概念 Duration&#xff08;时间段&#xff09; 概念 表示两个时间点之间的时间差。时间单位 小时&#xff08;hours&#xff09;&#xff1a;std::chrono::hours 分钟&#xff08;minutes&#xff09;&#xff1a;std::chrono::minutes…

Vue3 源码解读系列(十四)——内置组件

内置组件 问题&#xff1a;内置组件为什么不需要引入&#xff1f; 答&#xff1a;内置组件默认是全局引入的。 <Teleport> 定义 /*** Teleport 组件定义*/ const Teleport {__isTeleport: true,// 组件创建和更新process(nl, n2, container, anchor, parentComponent,…

echarts 横向柱状图示例

该示例有如下几个特点&#xff1a; ①实现tooltip自定义样式&#xff08;echarts 实现tooltip提示框样式自定义-CSDN博客&#xff09; ②实现数据过多时滚动展示&#xff08;echarts 数据过多时展示滚动条-CSDN博客&#xff09; ③柱状图首尾展示文字&#xff0c;文字内容嵌入图…

SpringCloud相关

文章目录 Gateway动态路由灰度策略 FeignRibbon SpringCloud五大组件分别对应&#xff08;1&#xff09;服务注册与发现&#xff08;2&#xff09;客服端负载均衡&#xff08;3&#xff09;断路器&#xff08;4&#xff09;服务网关&#xff08;5&#xff09;分布式配置 Gatewa…

力扣刷题第二十六天--二叉树

前言 昨天看总决赛&#xff0c;差距太大&#xff0c;看的没意思&#xff0c;真的是一点变通没有啊。难受&#xff0c;没有写题的状态了。大概率是最后一次看比赛了&#xff0c;青春已复过&#xff0c;白日忽相催。召唤师要和生活对线了。英雄们的语音&#xff0c;台词&#xf…

【LeetCode】1773. 统计匹配检索规则的物品数量

1773. 统计匹配检索规则的物品数量 难度&#xff1a;简单 题目 给你一个数组 items &#xff0c;其中 items[i] [typei, colori, namei] &#xff0c;描述第 i 件物品的类型、颜色以及名称。 另给你一条由两个字符串 ruleKey 和 ruleValue 表示的检索规则。 如果第 i 件物…

thonny的汉字编码是UTF-8,如何才能转为GB2312?

>>> chinese_str "你" >>> gb2312_str chinese_str.encode(GB2312) >>> print(gb2312_str) b\xe4\xbd\xa0 >>> print(chinese_str.encode(GB2312)) b\xe4\xbd\xa0 一个晚上了&#xff0c;就是找不到方法。好在知道问题在哪里…

Android Studio常见问题

Run一直是上次的apk 内存占用太大&#xff0c;导致闪退

R语言——taxize(第二部分)

taxize&#xff08;第二部分&#xff09; 3. taxize 文档中译3.10. classification&#xff08;根据类群ID检索分类阶元层级&#xff09;示例1&#xff1a;传递单个ID值示例2&#xff1a;传递多个ID值示例3&#xff1a;传递单个名称示例4&#xff1a;传递多个名称示例5&#xf…

【C++】传递‘类非静态成员函数’用作回调函数

在C语言中&#xff0c;传递函数指针是非常常见的操作。 在C语言中&#xff0c;使用C语言一致的方法传递全局函数指针&#xff0c;或者传递静态函数指针也很常见。 不过如果遇到想传递非静态成员函数时&#xff0c;可以参考以下示例代码。 #ifndef _WORKER_HPP_ #define _WOR…

详解FreeRTOS:二值信号量和计数信号量(高级篇—2)

目录 1、二值信号量 1.1、二值信号量运行机制 1.2、创建二值信号量 1

2023.11.18 -自用hadoop高可用环境搭建命令

启动hadoop高可用环境 # 1.先恢复快照到高可用环境 # 2.三台服务器启动zookeeper服务 [rootnode1 ~]# zkServer.sh start [rootnode2 ~]# zkServer.sh start [rootnode3 ~]# zkServer.sh start 查看服务状态: [rootnode]# zkServer.sh status 关闭zk服务的命令是: [rootnode]# …

C#入门(5):数组、一维数组,二维数组、交错数组、数组复制

在C#中&#xff0c;数组是一种用于存储相同类型元素的数据结构。数组提供了一种有序、索引访问的方式&#xff0c;使得可以通过索引快速访问和修改数组中的元素。在C#中&#xff0c;主要有一维数组和二维数组两种类型。 一维数组&#xff08;Single-Dimensional Array&#xf…

SpringCloud -Token传递之Feign

目录 方法一 RequestHeader 方法二 使用Feign的Interceptor 步骤一 实现RequestInterceptor接口 步骤二&#xff1a;配置Feign 通常微服务对于用户认证信息解析有两种方案 在 gateway 就解析用户的 token 然后路由的时候把 userId 等相关信息添加到 header 中传递下去。在…

YOLOv5 配置C2模块构造新模型

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客 &#x1f366; 参考文章&#xff1a;365天深度学习训练营 &#x1f356; 原作者&#xff1a;[K同学啊] &#x1f680; 文章来源&#xff1a;[K同学的学习圈子](https://www.yuque.com/mingtian-fkmxf/zxwb4…

【Linux】Linux下的基础IO

❤️前言 大家好&#xff01;今天这篇博客和大家聊一聊关于Linux下的基础IO。 正文 在阅读本篇博客之前&#xff0c;请大家先回顾一下C语言文件操作的一些方法&#xff0c;这里可以看看我之前记录的一些内容&#xff1a; 【C语言】C语言成长之路之文件操作_MO_lion的博客-CSD…

mysql使用--表达式和函数

1.表达式 如&#xff1a;11&#xff0c;一般包含操作数&#xff0c;运算符。 _1.操作数 MYSQL中最常用的操作数有以下几种 (1).常数 (2).列名&#xff0c;针对某个具体的表&#xff0c;它的列名可被当作表达式的一部分 (3).函数调用 一个函数用于完成某个特定的功能。比如NOW()…

【PyQt小知识 - 3】: QComboBox下拉框内容的设置和更新、默认值的设置、值和下标的获取

QComboBox 内容的设置和更新 from PyQt5.QtWidgets import * import sysapp QApplication(sys.argv)mainwindow QMainWindow() mainwindow.resize(200, 200) # 设置下拉框 comboBox QComboBox(mainwindow) comboBox.addItems([上, 中, 下])button QPushButton(更新, main…

Colab跑项目

这里写目录标题 Colab文件目录路径显示更改colab当前工作文件夹Colab挂载谷歌云盘colab使用命令&#xff08;从这开始看&#xff0c;前面no zuo no die)最紧要&#xff0c;首先&#xff0c;修改笔记本设置使用启用gpu![在这里插入图片描述](https://img-blog.csdnimg.cn/591a6c…

NAS层协议栈学习笔记

NAS(Non-Access Stratum)是无线网络中非接入层及包括移动性管理(MM)和会话管理(SM)协议 &#xff0c;在5G(NR)系统中连接管理(Connection Management)用于建立和释放UE与AMF之间的控制面(CP)信令连接。 5G中移动性管理是通过NAS信令在UE与核心网之间进行交互的&#xff0c;连接…