最全的接口自动化测试思路和实战:【推荐】混合测试自动化框架(关键字+数据驱动)

混合测试自动化框架(关键字+数据驱动)

关键字驱动或表驱动的测试框架

  这个框架需要开发数据表和关键字。这些数据表和关键字独立于执行它们的测试自动化工具,并可以用来“驱动"待测应用程序和数据的测试脚本代码,关键字驱动测试看上去与手工测试用例很类似。在一个关键字驱动测试中,把待测应用程序的功能和每个测试的执行步骤一起写到一个表中。

       这个测试框架可以通过很少的代码来产生大量的测试用例。同样的代码在用数据表来产生各个测试用例的同时被复用。

混合测试自动化框架

  最普遍的执行框架是上面介绍的所有技术的一个结合,取其长处,弥补其不足。这个混合测试框架是由大部分框架随着时间并经过若干项目演化而来的。

unittest关于测试报告展示用例名称的细节:

在unittest有两个内置属性,可以自定义用例名称

之前的效果:

 

 自动化测试相关教程推荐:

2023最新自动化测试自学教程新手小白26天入门最详细教程,目前已有300多人通过学习这套教程入职大厂!!_哔哩哔哩_bilibili

2023最新合集Python自动化测试开发框架【全栈/实战/教程】合集精华,学完年薪40W+_哔哩哔哩_bilibili

测试开发相关教程推荐

2023全网最牛,字节测试开发大佬现场教学,从零开始教你成为年薪百万的测试开发工程师_哔哩哔哩_bilibili

postman/jmeter/fiddler测试工具类教程推荐

讲的最详细JMeter接口测试/接口自动化测试项目实战合集教程,学jmeter接口测试一套教程就够了!!_哔哩哔哩_bilibili

2023自学fiddler抓包,请一定要看完【如何1天学会fiddler抓包】的全网最详细视频教程!!_哔哩哔哩_bilibili

2023全网封神,B站讲的最详细的Postman接口测试实战教学,小白都能学会_哔哩哔哩_bilibili

使用内置属性效果:

 

框架设计目标

  设计出来的框架是直接给测试人员,而且其他的测试人员只需要简单的向里面不断的补充测试用例即可;所以我们的框架设计必须三简化即操作简单,维护简单,扩展简单。

  设计框架的同时一定要结合业务流程,而不仅仅靠技术实现,其实技术实现不难,难点对业务流程的理解和把握。

  设计框架时要将基础的封装成公用的,如:get请求、post请求和断言封装成同基础通用类。

  测试用例要与代码分开,这样便于用例管理,采用数据驱动框架实现。

如下图所示:

  通过在excel录入测试用例,框架运行后自动进行用例执行,产生html网页版本的测试报告。

报告结果:

框架用到的技术点

1、语言:python

2、测试框架:unittest(assertEqual)或pytest

3、接口调用:requests(API非常简洁)

4、数据驱动:paramunittest (组装一定的格式数据就可以参数化)

5、数据管理:xlrd(读取excel文件数据)、configparser(读取配置文件)

6、数据格式的转换:ast,json

7、日志处理:logging ---清晰的执行过程,快速定位问题

8、测试报表:HTMLTestReportCN(由网友制作设计,显示清晰美观)

9、测试邮件发送测试报告:smtplib(邮件内容格式设置)、email(收发邮件)

10、持续集成:Jenkins(按策略执行接口测试脚本)

(推荐)混合测试自动化框架(关键字+数据驱动)

数据源实现:

数据源目前使用excel,数据如下:

链接:https://pan.baidu.com/s/1VvvGYRvGbElSlP6ngg0ktw
提取码:ppua

思路:使用python读取excel数据;使用xlrd3

框架01:新建项目API_KEY_WORD_TEST_FRAME;

步骤1、在项目根目录下新建common的py文件夹和conf的普通文件夹;samples文件夹是用来写测试代码的demo;

步骤2、在conf下新建config.ini文件

 编写代码:

[default]# 主机地址
hosts = api.weixin.qq.com
步骤3、在common下新建ini_file_utils.py文件和config_utils.py文件

ini_file_utils.py文件如下:

 编写代码:

复制代码

# encoding: utf-8
# @author: Jeffrey
# @file: ini_file_utils.py
# @time: 2022/8/4 22:23
# @desc: 读取、写入ini文件
import os
import configparserclass IniFileUtils:  #和框架业务无关的底层代码==》公共底层代码def __init__(self,file_path):self.ini_file_path = file_pathself.conf_obj = configparser.ConfigParser()self.conf_obj.read(self.ini_file_path, encoding='utf-8')def get_config_value(self,section, key):value = self.conf_obj.get(section, key)return valuedef set_config_value(self,section, key, value):'''设置config.ini文件中的值'''self.conf_obj.set(section, key, value)config_file_obj = open(self.ini_file_path, 'w')self.conf_obj.write(config_file_obj)config_file_obj.close()if __name__ == '__main__':current_path = os.path.dirname(__file__)config_file_path = os.path.join(current_path, '../conf/config.ini')ini_file = IniFileUtils(config_file_path)print(ini_file.get_config_value('default', 'HOSTS'))

复制代码

config_utils.py文件如下:

 编写代码:

复制代码

# encoding: utf-8
# @author: Jeffrey
# @file: config_utils.py
# @time: 2022/8/4 22:26
# @desc: 封装读取ini文件的方法import os
from common.ini_file_utils import IniFileUtilscurrent_path = os.path.dirname(os.path.abspath(__file__))
config_file_path = os.path.join(current_path, '../conf/config.ini')class LocalConfig():  # #和框架业务有关系的底层代码def __init__(self,file_path = config_file_path):self.ini_file_obj = IniFileUtils(file_path)@propertydef get_hosts(self):'''获取ini文件中的hosts值'''hosts_value = self.ini_file_obj.get_config_value('default', 'hosts')return hosts_valuelocal_config = LocalConfig()if __name__ == '__main__':print(local_config.get_hosts)

复制代码

步骤4、在samples文件下编写线性脚本,读取excel中的合并单元格

Excel表格如下:

 

 

 

 编写代码:

复制代码

# encoding: utf-8
# @author: Jeffrey
# @file: demo01.py
# @time: 2022/8/7 14:53
# @desc:  excel中合并单元格的读取
import xlrd3work_book = xlrd3.open_workbook('test_data.xlsx')  # 创建一个工作簿对象
sheet_obj = work_book.sheet_by_name('Sheet1')  # 创建一个表格对象
print(sheet_obj.cell_value(1,2))  # 获取单元格的值(行,列),从0开始计算,行列实际序号-1
print(sheet_obj.cell_value(7,3))  # 获取单元格的值print(sheet_obj.cell_value(1,0))  # 合并的单元格,获取的值为空
print(sheet_obj.cell_value(7,0))  # 合并的单元格,获取的值为空# 包含四个元素(起始行,结束行,其实列,结束列) 包前不包后
print(sheet_obj.merged_cells)  # [(1, 5, 0, 1), (5, 9, 0, 1)]
# 思路步骤一:判断一个单元格是否是合并的单元格
x = 3 ; y = 0
if x>=1 and x<5:if y>=0 and y<1:print('合并单元格')else:print('非合并单元格')
else:print('非合并单元格')# 思路步骤二:for循环的写法
for (min_row,max_row,min_col,max_col) in [(1, 5, 0, 1), (5, 9, 0, 1)]:print(min_row,max_row,min_col,max_col)# 思路步骤三:把思路一和二整合进单元格判断是否是合并的单元格
x = 6 ; y = 0
for (min_row,max_row,min_col,max_col) in sheet_obj.merged_cells:if x >= min_row and x < max_row:if y >= min_col and y < max_col:print('合并单元格')breakelse:print('非合并单元格')else:print('非合并单元格')# 思路步骤四:让合并单元格的值都等于合并第一个单元格的值,非合并单元格为原值
x = 4 ; y = 1
cell_value = None
for (min_row,max_row,min_col,max_col) in sheet_obj.merged_cells:if x >= min_row and x < max_row:if y >= min_col and y < max_col:cell_value = sheet_obj.cell_value(min_row,min_col)breakelse:cell_value = sheet_obj.cell_value(x, y)else:cell_value = sheet_obj.cell_value(x, y)
print(cell_value)# 把上诉代码做成一个方法
def get_merged_cell_value(row_index,col_index):cell_value = Nonefor (min_row, max_row, min_col, max_col) in sheet_obj.merged_cells:if row_index >= min_row and row_index < max_row:if col_index >= min_col and col_index < max_col:cell_value = sheet_obj.cell_value(min_row, min_col)breakelse:cell_value = sheet_obj.cell_value(row_index, col_index)else:cell_value = sheet_obj.cell_value(row_index, col_index)return cell_valueprint(get_merged_cell_value(8,0))# 获取excel中所有的数据 线性脚本
# 步骤一:线性脚本
head = sheet_obj.row_values(0)
print(head)  # ['学习课程', '步骤序号', '步骤操作', '完成情况']
excel_list = []
excel_dict = {}
excel_dict[head[0]] = get_merged_cell_value(1,0)
excel_dict[head[1]] = get_merged_cell_value(1,1)
excel_dict[head[2]] = get_merged_cell_value(1,2)
excel_dict[head[3]] = get_merged_cell_value(1,3)
excel_list.append(excel_dict)
print(excel_list)# 步骤二: 使用for循环封装
head = sheet_obj.row_values(0)
excel_data_list = []
for j in range(1,sheet_obj.nrows):row_value_dict = {}for i in range(sheet_obj.ncols):row_value_dict[head[i]] = get_merged_cell_value(j,i)excel_data_list.append(row_value_dict)
print(excel_data_list)for data in excel_data_list:print(data)

复制代码

步骤5、在common下新建excel_file_utils.py文件

 

 编写代码:

复制代码

# encoding: utf-8
# @author: Jeffrey
# @file: excel_file_utils.py
# @time: 2022/8/7 15:52
# @desc: 封装读取excel文件
import os
import xlrd3class ExcelFileUtils():def __init__(self,excel_file_path, sheet_name):self.excel_file_path = excel_file_pathself.sheet_name = sheet_nameself.sheet_obj = self.get_sheet()def get_sheet(self):'''根据excel路径已经表名称 创建一个表格对象'''workbook = xlrd3.open_workbook(self.excel_file_path)sheet = workbook.sheet_by_name(self.sheet_name)return sheetdef get_row_count(self):'''获取表格实际行数'''row_count = self.sheet_obj.nrowsreturn row_countdef get_col_count(self):'''获取表格的实际列数'''col_count = self.sheet_obj.ncolsreturn col_countdef get_merged_cell_value(self,row_index, col_index):''':param row_index: 行下标:param col_index: 列下标:return: 获取单元格的内容'''cell_value = Nonefor (min_row, max_row, min_col, max_col) in self.sheet_obj.merged_cells:if row_index >= min_row and row_index < max_row:if col_index >= min_col and col_index < max_col:cell_value = self.sheet_obj.cell_value(min_row, min_col)breakelse:cell_value = self.sheet_obj.cell_value(row_index, col_index)else:cell_value = self.sheet_obj.cell_value(row_index, col_index)return cell_valuedef get_all_excel_data_list(self):'''获取excel中所有的数据,以列表嵌套字典的形式'''excel_data_list = []head = self.sheet_obj.row_values(0)for j in range(1,self.get_row_count()):row_value_dict = {}for i in range(self.get_col_count()):  # sheet_obj.ncols 动态获取表格多少列row_value_dict[head[i]] = self.get_merged_cell_value(j,i)excel_data_list.append(row_value_dict)return excel_data_listif __name__ == '__main__':current_path = os.path.dirname(__file__)file_path = os.path.join(current_path, '../samples/test_data.xlsx')excel_obj = ExcelFileUtils(file_path, 'Sheet1')print(excel_obj.get_all_excel_data_list())print(excel_obj.get_col_count())

复制代码

测试执行结果:

步骤6、在项目根目录下新建test_data普通文件夹,把测试用例文件放里面

 

步骤7、在common下新建testcase_data_utils.py文件把测试用例的数据转换成框架需要用到的格式

 编写代码:

复制代码

# encoding: utf-8
# @author: Jeffrey
# @file: testcase_data_utils.py
# @time: 2022/8/7 17:02
# @desc: 数据格式转换:把测试用例数据转换成框架需要用到的格式
import os
from common.excel_file_utils import ExcelFileUtilscurrent_path = os.path.dirname(__file__)
file_path = os.path.join(current_path, '../test_data/testcase_infos.xlsx')class TestCaseDataUtils:def __init__(self):self.test_data = ExcelFileUtils(excel_file_path=file_path,sheet_name='Sheet1')\.get_all_excel_data_list()def convert_testcase_data_to_dict(self):'''把excel中的测试用例数据转换为[{},{},{}]转换成{"":[],"":[],"":[]}'''test_case_data_dict = {}for row_data in self.test_data:test_case_data_dict.setdefault( row_data['测试用例编号'],[] )\.append(row_data)return test_case_data_dictdef convert_testcase_data_to_list(self):'''把数据{"":[],"":[],"":[]} 转换成["case_id":key,"case_step":value]'''test_case_data_list = []for key, value in self.convert_testcase_data_to_dict().items():case_info_dict = {}case_info_dict['case_id'] = keycase_info_dict['case_step'] = valuetest_case_data_list.append(case_info_dict)return test_case_data_listif __name__ == '__main__':# print(TestCaseDataUtils().convert_testcase_data_to_dict())print(TestCaseDataUtils().convert_testcase_data_to_list())

复制代码

convert_testcase_data_to_dict()方法的目的是把用例数据以用例编号和用例数据分开

'''把excel中的测试用例数据转换为[{},{},{}]转换成{"":[],"":[],"":[]}'''

查看执行结果:

 总结:

 光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

如果对你有帮助的话,点个赞收个藏,给作者一个鼓励。也方便你下次能够快速查找。

如有不懂还要咨询下方小卡片,博主也希望和志同道合的测试人员一起学习进步

在适当的年龄,选择适当的岗位,尽量去发挥好自己的优势。

我的自动化测试开发之路,一路走来都离不每个阶段的计划,因为自己喜欢规划和总结,

测试开发视频教程、学习笔记领取传送门!!

 

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

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

相关文章

mount /dev/mapper/centos-root on sysroot failed处理

今天发现centos7重启开不进去系统 通过查看日志主要告警如下 修复挂载目录 xfs_repair /dev/mapper/centos-root不行加-L参数 xfs_repair -L /dev/mapper/centos-root重启 reboot

云课五分钟-0Cg++默认版本和升级-std=c++17

前篇&#xff1a; 云课五分钟-0B快速排序C示例代码-注释和编译指令 视频&#xff1a; 云课五分钟-0Cg默认版本和升级-stdc17 文本&#xff1a; 在Linux系统中&#xff0c;可以通过以下步骤升级g&#xff1a; 打开终端&#xff0c;使用root权限或者sudo权限登录。输入以下命令…

基于灰狼算法(GWO)优化的VMD参数(GWO-VMD)

代码的使用说明 基于灰狼算法优化的VMD参数 代码的原理 基于灰狼算法&#xff08;Grey Wolf Optimizer, GWO&#xff09;优化的VMD参数&#xff08;GWO-VMD&#xff09;是一种结合了GWO和VMD算法的优化方法&#xff0c;用于信号分解和特征提取。 GWO是一种基于群体智能的优化…

lv11 嵌入式开发 ARM指令集中(伪操作与混合编程) 7

目录 1 伪指令 2 伪操作 3 C和汇编的混合编程 4 ATPCS协议 1 伪指令 本身不是指令&#xff0c;编译器可以将其替换成若干条等效指令 空指令NOP 指令LDR R1, [R2] 将R2指向的内存空间中的数据读取到R1寄存器 伪指令LDR R1, 0x12345678 R1 0x12345678 LDR伪指令可以将任…

小米真无线耳机 Air 2s产品蓝牙配对ubuntu20.04 笔记本电脑

小米真无线耳机 Air 2s产品蓝牙配对ubuntu20.04 笔记本电脑 1.我的笔记本是 22款联想拯救者y9000k&#xff0c;安装了双系统&#xff0c;ubuntu20.04。 2.打开耳机&#xff0c;按压侧面按钮2秒&#xff0c;指示灯显示白色闪烁。 3.打开ubunru20.04 系统右上角wifi的位置&…

vulnhub靶场—matrix-breakout-2-morpheus靶机

一&#xff0c;实验环境 靶机ip&#xff1a;192.168.150.131攻击机ip&#xff1a;192.168.150.130 二&#xff0c;信息收集 arp-scan -l 扫描网段&#xff0c;寻找靶机ip 使用工具nmap进行端口扫描 nmap -A -T4 -p- 192.168.150.131 通过信息收集发现了靶机有80和81这两个…

HP惠普光影精灵7笔记本Victus by HP 16.1英寸游戏本16-d0000原装出厂Windows11.21H2预装OEM系统

下载链接&#xff1a;https://pan.baidu.com/s/1LGNeQR1AF1XBJb5kfZca5w?pwdhwk6 提取码&#xff1a;hwk6 可适用的型号&#xff1a; 16-d0111tx&#xff0c;16-d0112tx&#xff0c;16-d0125tx&#xff0c;16-d0127tx&#xff0c;16-d0128tx&#xff0c;16-d0129tx&#…

JAVA多线程(5)

JAVA多线程(5) 线程安全问题概述 卖票问题分析 单窗口卖票 一个窗口(单线程)卖100张票没有问题 单线程程序是不会出现线程安全问题的 多个窗口卖不同的票 3个窗口一起卖票,卖的票不同,也不会出现问题 多线程程序,没有访问共享数据,不会产生问题 多个窗口卖相同的票 3个窗口…

【Go入门】 Go如何使得Web工作

【Go入门】 Go如何使得Web工作 前面小节介绍了如何通过Go搭建一个Web服务&#xff0c;我们可以看到简单应用一个net/http包就方便的搭建起来了。那么Go在底层到底是怎么做的呢&#xff1f;万变不离其宗&#xff0c;Go的Web服务工作也离不开我们第一小节介绍的Web工作方式。 w…

竞赛选题 深度学习花卉识别 - python 机器视觉 opencv

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &a…

Canal+Kafka实现MySQL与Redis数据同步(一)

CanalKafka实现MySQL与Redis数据同步&#xff08;一&#xff09; 前言 在很多业务情况下&#xff0c;我们都会在系统中加入redis缓存做查询优化。 如果数据库数据发生更新&#xff0c;这时候就需要在业务代码中写一段同步更新redis的代码。 这种数据同步的代码跟业务代码糅合…

公司内部网络架设悟空CRM客户管理系统 cpolar无需公网IP实现内网,映射端口外网访问

1、什么是内网穿透&#xff1f; 内网穿透&#xff0c;即内网映射&#xff0c;内网IP端口映射到外网的过程。是一种主动的操作&#xff0c;需要本人一些内网的权限。比如在公司自己电脑&#xff0c;将办公OA发布到互联网&#xff0c;然后提供外网在家或出差在外连接访问。 可以…

本地开发环境和服务器传输数据的几种方法

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【洛谷 B2002】Hello,World!(顺序结构)

Hello,World! 题目描述 编写一个能够输出 Hello,World! 的程序。 提示&#xff1a; 使用英文标点符号&#xff1b;Hello,World! 逗号后面没有空格。H 和 W 为大写字母。 输入格式 输出格式 样例 #1 样例输入 #1 无样例输出 #1 Hello,World!思路 #include 是一个预处…

隐式转换导致索引失效的原因

Num1 int Num2 varchar Str1不能为null Str2可null 例子1&#xff1a; 结果&#xff1a;124非常快&#xff0c;0.001~0.005秒出结果。3最慢&#xff0c;4~5秒出结果。 查询执行计划&#xff1a;124索引扫描。3全表扫描。 解释&#xff1a;首先四个23都产生隐式转换&#x…

C语言——2.安装并使用VS

文章目录 1.编译器是什么2.编译器的选择2.1.VS2019/2022 的初步了解2.2.为什么不选择其他编译器呢&#xff1f; 3.编译器的安装过程&#xff08;保姆级别教学&#xff09;3.1.检查电脑版本3.2.下载安装包3.3.选择安装选项3.4.重启电脑3.5.创建账户登录3.6.颜色配置3.7.VS&#…

用GPT 搭建一个占星术、解梦、塔罗牌占卜和命理学服务

今天来尝试我们的占星术、解梦、塔罗牌占卜和命理学服务&#xff0c;揭开宇宙的奥秘并获得自我认识 聊天 GPT API 集成的 HTML5 模板。我们的目标是提供易于使用且高度可定制的 API 代码&#xff0c;使您能够训练自己的人工智能解决方案并将其添加到提示中。 我们的产品是可定…

Backtrader绘图cerebro.plot报错问题的处理

Backtrader绘图cerebro.plot报错问题的处理 1.问题描述 在jupyter 中使用BackTrader &#xff0c;使用绘图功能时&#xff1a; cerebro.plot() 提示错误&#xff1a;ValueError: Axis limits cannot be NaN or Inf 由于backtrader 要求有7列数据&#xff0c;最后一列openint…

springcloud新闻发布系统源码

开发技术&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;nodejs&#xff0c;idea&#xff0c;vscode springcloud springboot mybatis vue elementui 功能介绍&#xff1a; 用户端&#xff1a; 登录注册 首页显示搜索新闻&#xff0c;新闻分类&#xff0c;新闻列表…

Redis 访问控制列表(ACL)

Redis ACL 关于 Redis ACL与旧版本兼容ACL helpACL 配置模式redis.conf 配置模式外部 ACL File 配置模式 ACL 规则总结 关于 Redis ACL Redis ACL (访问控制列表) 是 Access Control List 的缩写&#xff0c;它允许某些连接在可以执行的命令和可以访问的密钥方面受到限制。它…