【接口自动化】06-轻量级框架封装(完):日志监控、数据驱动及断言
一、前言上一期我们知道了统一接口请求的轻量级框架的封装那么我们轻量级框架封装还未结束我们本期继续介绍轻量级框架封装即日志监控、数据驱动以及断言等等二、轻量级框架封装日志监控封装日志在开发中是很重要的同时在自动化测试中也很重要因为日志它可以记录程序在运行的时候发生的一些细节信息从而帮助我们了解程序的运行时过程进一步帮助我们判断排除程序出现的问题。在Python中进行日志记录有两种内置标准库logging【常用】第三方库loggru我们会选择内置的标准库logging因为他能够和pytest很好的集成。1、在pytest中启用日志记录如何启用呢将下述的配置内容放入到我们的pytest.ini配置文件中# 日志相关配置 # 日志文件存储路径相对项目根目录日志会输出到logs文件夹下的frame.log文件log_file./logs/frame.log# 日志输出级别低于该级别的日志不会写入文件# 级别优先级从小到大DEBUG调试 INFO信息 WARNING警告 ERROR错误 CRITICAL严重故障log_file_levelINFO# 日志打印格式模板# %(asctime)s日志打印的时间# %(levelname)s日志级别名称INFO/WARNING等# %(message)s自定义输出的日志内容log_file_format%(asctime)s %(levelname)s %(message)s解释日志格式字符串占位符标识作用说明%(asctime)s打印日志记录的时间%(levelname)s打印日志级别文字DEBUG/INFO/WARNING等%(message)s打印自定义输出的日志/报错信息主体%(levelno)s打印日志级别对应的数字编号%(pathname)s打印当前执行文件完整路径等价于sys.argv[0]%(filename)s打印当前执行的程序文件名%(funcName)s打印输出日志所在的函数名%(lineno)d打印打印日志代码所在的行号%(thread)d打印当前线程ID数字%(threadName)s打印当前线程名称%(process)d打印当前进程ID数字上述我们只是将日志给启用但是日志里面的内容我们需要一个日志对象来进行封装。2、创建日志对象logger使用logging.getLogger(名字)来创建# 导入日志模块的包importlogging# 创建日志对象loggerlogging.getLogger(__name__)# 使用__name__可以自动生成名字loggerlogging.getLogger(my_logger)# 自己指定名字3、使用logger来记录日志用法如下所示# 导入日志模块的包importlogging# 创建日志对象loggerlogging.getLogger(__name__)# 使用__name__可以自动生成名字# 开始记录日志logger.debug()# 记录一个debug级别的日志logger.info()# 记录一个info级别的日志logger.error()# 记录一个error级别的日志注意日志的内容必须是字符串如果做到字符串我们使用一个占位符然后将数据填充进去最终我们的数据也变为字符串了# 这个输出格式我们在Python语法基础中也有介绍过的data{1,2,3}logger.error(f数据的内容{data})4、给接口打上日志记录上一期我们对接口请求进行了轻量级的统一封装importrequestsclassRequestUtil:# 首先将session做为类对象供给大家共用sessrequests.session()# 创建一个参数 用于共用公共参数params{application:app,application_client_type:android,}# 创建一个方法构造请求defsend_request(self,**kwargs):# 使用不定长的关键字参数# 完善动态参数ifparamsinkwargs:# 不存在就添加存在就是修改kwargs[params].update(self.params)# 发送请求respself.sess.request(**kwargs)returnresp那么现在我们就需要给这个所封装的接口请求打上我们的日志便于我们的观察我们需要打上哪一些日志呢前置# 导入日志框架importlogging# 创建出日志对象loggerlogging.getLogger(__name__)1、请求前# 1、打印请求入参日志请求前 logger.info(f【发起HTTP请求】原始请求参数:{kwargs})2、记录请求# 2、打印请求日志logger.info(f【请求参数合并完成】最终请求params:{kwargs.get(params)})3、记录响应# 3、打印响应日志请求后 logger.info(f【接口响应结果】状态码{resp.status_code}, 响应头{dict(resp.headers)})try:# 优先打印json格式响应体resp_jsonresp.json()# 因为只有你的响应内容是json字符串那么才可以使用json()方法logger.info(f【响应JSON数据】{resp_json})exceptException:# 非json接口打印原始文本logger.info(f【响应文本数据】{resp.text})完整代码importrequests# 导入日志框架importlogging# 创建出日志对象loggerlogging.getLogger(__name__)classRequestUtil:# 首先将session做为类对象供给大家共用sessrequests.session()# 创建一个参数 用于共用公共参数params{application:app,application_client_type:android,}# 创建一个方法构造请求defsend_request(self,**kwargs):# 使用不定长的关键字参数# 1、打印请求入参日志请求前logger.info(f【发起HTTP请求】原始请求参数{kwargs})# 完善动态参数ifparamsinkwargs:# 不存在就添加存在就是修改kwargs[params].update(self.params)# 2、打印请求日志logger.info(f【请求参数合并完成】最终请求params:{kwargs.get(params)})# 发送请求respself.sess.request(**kwargs)# 3、打印响应日志请求后 logger.info(f【接口响应结果】状态码{resp.status_code}, 响应头{dict(resp.headers)})try:# 优先打印json格式响应体resp_jsonresp.json()# 因为只有你的响应内容是json字符串那么才可以使用json()方法logger.info(f【响应JSON数据】{resp_json})exceptException:# 非json接口打印原始文本logger.info(f【响应文本数据】{resp.text})returnresp结果我现在day05这个目录下运行那么我们就会在当前目录下创建一个logs文件夹打开里面有一个frame.log文件梳理逻辑上述完成日志的封装之后我们接下来就实现数据驱动测试的封装三、轻量级框架封装数据驱动封装我们需要实现使用数据文件去驱动测试用例也就是代码和数据文件的分离。具体的实现思路设计YAML数据文件格式加载YAML完成数据驱动测试1、设计YAML数据文件格式数据文件名的格式需要和测试用例名的格式一致唯一的区别就是测试用例名的test_改为ddt_什么意思呢比如你的一个测试用用例是test_tan那么现在你这个测试用例所对应的YMAL文件命名为ddt_tan这样一来你一看都是tan那么你就可以知道哪一个测试用例对应了哪一个数据驱动文件。如下那么我们在数据驱动文件中写什么呢上述我们的数据文件中定制的有两个内容一个是Allure报告的定制另一个是接口请求的内容-feature:首页模块story:首页接口title:首页接口请求成功request:method:geturl:http://116.62.63.211/shop/api.phpparams:s:index/index2、加载YAML完成数据驱动测试怎么去读取数据呢就看下面的图解你要去读取数据那么你就得让一个东西来帮助我们这个东西其实就是一个标记pytest.mark.parametrizepytest.mark.parametrize(变量名,打开文件并读取)def用例():代码如下importallureimportpytestfrom commons.request_utilimportRequestUtilfrom commons.yml_utilimportYmlUtilpytest.mark.parametrize(case_info,YmlUtil(rE:\python_project\basic-python-grammar-learning\api_framwor\day06\ddt_tan.yaml).read())deftest_tan(case_info):# 读取数据文件中的内容 featurecase_info[feature]storycase_info[story]titlecase_info[title]requestcase_info[request]# 此处定制Allure报告 allure.dynamic.feature(feature)allure.dynamic.story(story)allure.dynamic.title(title)respRequestUtil().send_request(**request)# 请求完毕之后他会有返回值那么此时我们就可以断言assertresp.json()[code]0结果打开YAML文件中的文件地址可以动态获取Path(__file__)获取当前文件的路径str(Path(__file__).parent)得到当前文件所在的目录变动如下图所示代码importallureimportpytestfrom pathlibimportPathfrom commons.request_utilimportRequestUtilfrom commons.yml_utilimportYmlUtilcase_pathstr(Path(__file__).parent)pytest.mark.parametrize(case_info,YmlUtil(case_path/ddt_tan.yaml).read())deftest_tan(case_info):# 读取数据文件中的内容 featurecase_info[feature]storycase_info[story]titlecase_info[title]requestcase_info[request]# 此处定制Allure报告 allure.dynamic.feature(feature)allure.dynamic.story(story)allure.dynamic.title(title)respRequestUtil().send_request(**request)# 请求完毕之后他会有返回值那么此时我们就可以断言assertresp.json()[code]0结果四、轻量级框架封装JSON断言的封装我们会使用一种工具通过这个工具来对JSON对象进行一些深度的比较1、先安装对应的模块pip install deepdiff2、简单演示怎么使用我们假设有两个字典(JSON在Python中叫做字典)dict1{a:1,b:2,c:{d:3}}dict2{a:1,b:4,e:5}那么有以下的代码fromdeepdiffimportDeepDiff# 从deepdiff(从小写中)中导入DeepDiff大写dict1{a:1,b:2,c:{d:3}}dict2{a:1,b:4,e:5}diffDeepDiff(dict1,dict2)assertdiff{},diff# 如果是一样的话那么就断言成功了 后面的diff是为了打印详细信息3、deepdiff的特点1深度比较递归的比较有嵌套的数据结构2检测多种差异添加或者删除内容、值的变化、类型的变化3相等断言当两个数据一致(没有差异)时候返回的是空值可以使用结果{}进行断言。五、案例实战本实战中使用的接口文档是我们之前用的微信公众平台的接口文档老铁们可参考Jmeter接口实战1、基本样式创建test_weixin.py在里面写两个方法一个是用来获取鉴权码一个是用来上传文件的fromcommons.request_utilimportRequestUtil# 导入请求工具类deftest_get_token():passdeftest_upload():pass2、构造获取鉴权码的请求要素然后发送请求进行断言提取鉴权码get_ver{}# 全局变量deftest_get_token():methodGETurlhttps://api.weixin.qq.com/cgi-bin/tokenparams{grant_type:client_credential,appid:wx9335efa56e8cbb64,secret:0750c9411423c510fd0c2a1acdc32aa4}# 发送请求先实例化再掉里面的方法发送请求resRequestUtil().send_request(methodmethod,urlurl,paramsparams)# 断言expires_inres.json()[expires_in]assertexpires_in7200# 提取鉴权码access_tokenres.json()[access_token]get_ver[access_token]access_token3、我想只执行这个方法所以我就加一个标记pytest.mark.weixin此时需要在我们的配置文件中加入一个标记测试通过4、接下来就完成上传文件的这个接口那么将上述的获取鉴权码的接口复制一下进行修改即可因为大部分都是相似的得到的代码如下fromcommons.request_utilimportRequestUtil# 导入请求工具类importpytest get_ver{}# 全局变量pytest.mark.weixindeftest_get_token():methodGETurlhttps://api.weixin.qq.com/cgi-bin/tokenparams{grant_type:client_credential,appid:wx9335efa56e8cbb64,secret:0750c9411423c510fd0c2a1acdc32aa4}# 发送请求先实例化再掉里面的方法发送请求resRequestUtil().send_request(methodmethod,urlurl,paramsparams)# 断言expires_inres.json()[expires_in]assertexpires_in7200# 提取鉴权码access_tokenres.json()[access_token]get_ver[access_token]access_tokenpytest.mark.weixindeftest_upload():methodPOSTurlhttps://api.weixin.qq.com/cgi-bin/media/uploadimgparams{access_token:get_ver[access_token],}# 参数是文件files{media:open(rE:\python_project\basic-python-grammar-learning\api_framwor\data\弹简特头像.jpg,rb)# 文件的上传必须使用二进制的方式此处的路径我们可以使用之前的相对路径}# 发送请求先实例化再掉里面的方法发送请求resRequestUtil().send_request(methodmethod,urlurl,paramsparams,filesfiles)# 断言urlres.json()[url]asserthttpinurl结果通过六、总结接口自动化轻量级封装到目前我们轻量级的封装就暂时告一段落了我们接下来就总结一下我们的所学1、接口自动化测试的流程理解需求设计用例根据用例需求查找接口文档根据接口文档编写测试代码测试代码中包含请求的参数和预期的结果2、接口自动化测试中接口关联和数据驱动怎么做的接口关联先通过正则(字符串)或者JSONPATH(JSON)从上一个接口中提取数据把数据保存到全局变量中在下一个接口中使用变量即可完成关联数据驱动测试分析接口参数中会发生变化的内容不会变的东西不要用数据驱动将变化的部分写入yaml文件中因为YAML文件更便于阅读然后我们再编写代码从YAML文件中读取数据使用pytest的参数化标记进行数据驱动3、你们断言是怎么做的文本的响应类型判断包含或者相等实际上就是字符串之间的比较JSON的响应类型方法一使用JSONPATH提取目标数据对目标数据进行断言方法二DeepDiff对响应的内容进行断言4、你们的接口测试框架是怎么封装的首先我们要对技术栈有一个了解pytestrequestjsonpathallurelogging使用pytest作为一个基础的框架集成一些第三方插件对request进行一些统一请求的封装目的是进行公共参数的管理和日志的记录为了更方便的从json响应中提取数据进行管理和断言封装jsonpath利用allure进行测试报告的定制用例分组、自定义logo等等

相关新闻

90后35岁时我决定从运维转行:找一门越老越吃香的职业!

90后35岁时我决定从运维转行:找一门越老越吃香的职业!

90 后 35岁时我决定从运维转行:找一门越老越吃香的职业! 35岁之前,我总认为运维这个职位只要能熬得住、愿意加班的话,就一定能够熬出头来。但是真正做了几年之后才明白过来,巡检、处理报警、半夜救火等事情已经成为了…

2026/8/15 11:43:21 阅读更多 →
油田通信维护进入集成时代|鼎讯 RM-1000 与一线运维模式探索

油田通信维护进入集成时代|鼎讯 RM-1000 与一线运维模式探索

在石油行业,通信维护是一项 “看不见” 的工作,却直接影响着生产的 “看得见” 的效率。 从钻井平台到输油管道,从炼化基地到储油库区,每一个环节的通信设备都需要定期检测和维护。过去,这项工作依赖多个独立仪器配合完…

2026/8/12 20:34:00 阅读更多 →
智能体测开Day4

智能体测开Day4

昨日回顾今日讲解vi 编辑文件命令搜索命令替换命令创建session连接别人的Linux1.首先找到vmware中编辑->虚拟网络编辑器->选择仅主机点击更多设置->选择NAT模式->选择NAT设置->主机端口选择一个未被占用的端口号->虚拟机IP地址查找CentOS的IP->虚拟机端口…

2026/8/8 2:28:03 阅读更多 →

最新新闻

C++ 模拟实现 unordered_map 与 unordered_set

C++ 模拟实现 unordered_map 与 unordered_set

一、哈希表相关概念与特性总结1. 什么是哈希表哈希表(散列表):通过哈希函数,把关键字 key 映射到数组下标位置,直接访问元素,理想情况下查找、插入、删除时间复杂度接近 \(O(1)\)。数组叫做哈希桶数组&…

2026/8/16 2:58:50 阅读更多 →
AI产品工程实践:从快速迭代到全盘规划的策略选择

AI产品工程实践:从快速迭代到全盘规划的策略选择

1. 先想清楚,你的AI产品到底要解决什么问题做AI产品,最怕一上来就纠结“快速迭代”还是“全盘规划”。这就像盖房子,还没想好是盖个临时工棚还是百年住宅,就开始争论是用预制板快,还是打地基稳。方向错了,跑…

2026/8/16 2:58:50 阅读更多 →
CSS padding属性深度解析:从盒模型原理到响应式布局实战

CSS padding属性深度解析:从盒模型原理到响应式布局实战

1. 项目概述:为什么我们总在“盒子里”纠结 padding?如果你写过 CSS,那你一定和padding这个属性打过交道。它看起来很简单,不就是给元素加点内边距嘛。但在我十多年的前端开发生涯里,见过太多因为对padding理解不透彻而…

2026/8/16 2:58:50 阅读更多 →
运维转 Agent:Demo 跑通后,权限和日志才是真正翻车点

运维转 Agent:Demo 跑通后,权限和日志才是真正翻车点

聊《我用运维经验做了次 AI 项目,最先失效的是旧方法》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。摘要摘要:从自动化脚本到 AIOps Agent,很多运维工程师以为换个工具就能上手…

2026/8/16 2:58:50 阅读更多 →
EPLAN路径功能文本:提升电气设计效率与报表自动化的核心技巧

EPLAN路径功能文本:提升电气设计效率与报表自动化的核心技巧

1. 项目概述:为什么“路径功能文本”是EPLAN电气设计的效率倍增器在电气设计领域,尤其是涉及复杂控制系统(如PLC、DCS)的项目中,图纸的清晰度和信息的完整性直接决定了后续编程、调试和维护的效率。很多工程师在用EPLA…

2026/8/16 2:58:50 阅读更多 →
:实现微信、QQ提示音接管与 OpenCode 联动桌面宠物开发实录

:实现微信、QQ提示音接管与 OpenCode 联动桌面宠物开发实录

桌面宠物开发实录:实现微信、QQ提示音接管与 OpenCode 联动 文章目录桌面宠物开发实录:实现微信、QQ提示音接管与 OpenCode 联动摘要一、场景切入:我想要的不是"挂件",而是嵌入生活的角色二、总体架构:一个进…

2026/8/16 2:57:50 阅读更多 →

日新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

周新闻

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

基于阿里云与通义千问(Qwen)构建AI应用:从模型调用到生产部署的完整实践指南

如果你是一名开发者,最近可能已经感受到了AI大模型正在从“玩具”变成“生产力工具”的强烈信号。从代码补全到智能Agent,从本地部署到云端API,我们正处在一个技术栈快速重构的节点。然而,面对层出不穷的模型、框架和工具&#xf…

2026/8/16 0:00:54 阅读更多 →
工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/16 0:00:55 阅读更多 →
【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

【文章复现】非线性值迭代自适应动态规划(ADP):离散时间非线性系统的策略迭代自适应动态规划算法研究附Matlab代码

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。🍎 往期回顾关注个人主页:Matlab科研工作室👇 关注我领取海量matlab电子书和…

2026/8/16 0:03:55 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/14 13:40:53 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/14 14:06:45 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/15 2:35:29 阅读更多 →