pytest-html报告修改与汉化
前言
Pytest框架可以使用两种测试报告,其中一种就是使用pytest-html插件生成的测试报告,但是报告中有一些信息没有什么用途或者显示的不太好看,还有一些我们想要在报告中展示的信息却没有,最近又有人问我pytest-html生成的报告,能不能汉化?答案是肯定的,那么今天就教大家如何优化和汉化pytest-html测试报告解决上述问题
生成报告
我们先编写一个简单的测试代码,生成一份原始的测试报告,来看看哪些需要修改
测试代码
test_pytest_html.py
""" ------------------------------------ @Time : 2019/8/28 19:45 @Auth : linux超 @File : test_pytest_html.py @IDE : PyCharm @Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error! @QQ : 28174043@qq.com @GROUP: 878565760 ------------------------------------ """ import pytestdef login(username, password):"""模拟登录"""user = "linux超"pwd = "linux超哥"if user == username and pwd == password:return {"code": 1001, "msg": "登录成功", "data": None}else:return {"code": 1000, "msg": "用户名或密码错误", "data": None}test_data = [# 测试数据{"case": "用户名正确, 密码正确","user": "linux超","pwd": "linux超哥","expected": {"code": 1001, "msg": "登录成功", "data": None}},{"case": "用户名正确, 密码为空","user": "linux超","pwd": "","expected": {"code": 1000, "msg": "用户名或密码错误", "data": None}},{"case": "用户名为空, 密码正确","user": "","pwd": "linux超哥","expected": {"code": 1000, "msg": "用户名或密码错误", "data": None}},{"case": "用户名错误, 密码错误","user": "linux","pwd": "linux","expected": {"code": 1000, "msg": "用户名或密码错误", "data": None}} ]class TestLogin(object):@pytest.mark.parametrize("data", test_data)def test_login(self, data):result = login(data["user"], data["pwd"])assert result == data["expected"]if __name__ == '__main__':pytest.main(['-sv', "D:\PythonTest\MyPytestHtml\pytest_html_optimization", "--html", "report.html"])
原始报告
修改Environment
可以看到原始的测试报告里面的Environment中所有的信息和我们的被测系统的环境关系不是很大,主要的信息其实是一些开发环境,那么如果我想添加或者删除一些信息,比如删除Java_Home,添加测试接口地址该如何添加讷?
我们需要在项目的根目录新键contest.py文件,文件中添加如下代码
def pytest_configure(config):# 添加接口地址与项目名称config._metadata["项目名称"] = "Linux超博客园自动化测试项目v1.0"config._metadata['接口地址'] = 'https://www.cnblogs.com/linuxchao/'# 删除Java_Homeconfig._metadata.pop("JAVA_HOME")
修改后的效果
修改Summary
原始的Summary部分只显示了测试用例数及用例执行时间,那么如果我们想在这个位置添加测试人员等一些信息该如何实现?同样在conftest.py文件中添加如下代码
@pytest.mark.optionalhook def pytest_html_results_summary(prefix):prefix.extend([html.p("所属部门: xx测试中心")])prefix.extend([html.p("测试人员: Linux超")])
修改后的效果
修改Results
Results主要展示的是测试结果信息,而且这里也有一些不符合我们实际需求的信息,比如Test列显示的内容很长,它主要是测试用例所在的路径及测试类,测试用例及测试数据拼接而成的,可读性很差,从这个描述根本看不出来我们的测试用例测试的是什么,所以我们希望它能这样显示:测试+用例名称[user:用户名-pwd:密码] ,如:测试用户名正确,密码正确[user:Linux超-pwd:Linux超哥],下面我们就来实现这样的效果
优化Test
先手我们分析一波源码,看一下原始的测试报告的Test列表的信息是怎么生成的。找到我们pytest-html插件的安装位置,打开plugin.py文件,你会发现这样一块代码
1 class TestResult: 2 def __init__(self, outcome, report, logfile, config): 3 self.test_id = report.nodeid 4 if getattr(report, "when", "call") != "call": 5 self.test_id = "::".join([report.nodeid, report.when]) 6 self.time = getattr(report, "duration", 0.0) 7 self.outcome = outcome
第3行,5行,就是报告中Test信息的来源了,test_pytest_html.py::TestLogin::test_login[data0] 这样一条信息,实际是用例的nodeid,而【data0】是测试用例参数化时的每个参数,我之前写过一篇关于参数化方法@pytest.mark.parametrize("data", test_data)的参数ids作用的文章,ids的作用主要就是用来标记测试用例(不知道的可以去看一下那篇文章),增加测试用例执行后输出信息的可读性,因此我们可以使用这个参数来改变【data0】,让它显示我们的测试数据,ok,在我们的测试代码中添加并修改如下代码
# 改变输出结果 ids = ["测试:{}->[用户名:{}-密码:{}-预期:{}]".format(data["case"], data["user"], data["pwd"], data["expected"]) for data in test_data ]class TestLogin(object):# 添加ids参数@pytest.mark.parametrize("data", test_data, ids=ids)def test_login(self, data):result = login(data["user"], data["pwd"])assert result == data["expected"]
修改完之后再次执行我们的测试代码,生成测试报告
很遗憾,中文部分显示的都是乱码,还得继续修改
解决中文乱码
在conftest.py文件中继续添加如下代码
import pytest from py._xmlgen import html@pytest.mark.hookwrapper def pytest_runtest_makereport(item):outcome = yieldreport = outcome.get_result()getattr(report, 'extra', [])report.nodeid = report.nodeid.encode("utf-8").decode("unicode_escape") # 解决乱码
再次执行测试代码,查看报告输出
中文已经可以正常显示了,很开心,但是前面还是有一堆的目录及测试类,我仍然不想要,那么我们继续修改
删除多余部分
要删除前面多余的部分,接下来只能通过修改报告的html了,因为源码中我实在没找到在哪里能够修改这个显示,我们查看一下html报告的页面元素属性
看到这里,你想到用什么方法来修改了嘛?我想到的是使用js代码改变这个元素的innerText, 我们先实验一下,切换到【控制台】依次执行如下代码
// 找到Test列中所有的表格元素 var test_name = document.getElementBysClassName("col-name"); // 修改第1个表格的innerText属性 test_name[0].innerText = test_name[0].innerText.split("\[")[1].split(["\]")[0]; // 以[符号分割一次,再以]分割一次,得到目标字符串
以上带代码只能修改一个表格,所以要修改多个表格只能使用循环了,再次重写js代码
var case_name_td = document.getElementsByClassName("col-name")for(var i = 0; i < case_name_td.length; i++)try{case_name_td[i].innerText = case_name_td[i].innerText.split("\[")[1].split("\]")[0];}catch(err){// 如果表格中没有[]会抛异常,如果抛异常我就显示null,如果你想显示别的东西自己改吧,因为通常只要我们使用参数化就有[]显示case_name_td[i].innerText = "null";}
js代码我们已经写好了, 但是我们要放在哪里讷,又是个问题?通过查看报告的html源码我发现在html代码的开头引入了这样一些代码
在pytest-html插件的源码中,发现插件的resource目录下有一个main.js文件,里面的代码就是上述html代码中的js脚本,一模一样的
而且在main.js中确实存在一个init()方法,通过以上分析,应该不难猜测生成测试报告时,会自动把main.js文件加载到html中,而且是从init()方法开始的,因此我们尝试一下把我们编写的js代码放到init()方法内部实验一下
function init () {reset_sort_headers();add_collapse();show_filters();toggle_sort_states(find('.initial-sort'));find_all('.sortable').forEach(function(elem) {elem.addEventListener("click",function(event) {sort_column(elem);}, false)});// 修改用例报告显示的用例名称 add by linux超var case_name_td = document.getElementsByClassName("col-name")for(var i = 0; i < case_name_td.length; i++)try{case_name_td[i].innerText = case_name_td[i].innerText.split("\[")[1].split("\]")[0];}catch(err){// 如果表格中没有[]会抛异常,如果抛异常我就显示null,如果你想显示别的东西自己改吧,因为通常只要我们使用参数化就有[]显示case_name_td[i].innerText = "null";}};
添加完之后记得保存,再次执行测试代码,查看测试报告
修改后的效果
你没有看错,确实成功了,小小成就感还是有的,哈哈!
删除Links
报告中的links从来没看见有内容过,所以我打算把这一列删除,在contest.py文件中添加如下代码
@pytest.mark.optionalhook def pytest_html_results_table_header(cells):cells.pop(-1) # 删除link列@pytest.mark.optionalhook def pytest_html_results_table_row(report, cells):cells.pop(-1) # 删除link列
修改后的效果
增加失败截图与用例描述
用例添加失败截图和添加一列用例的描述信息,在之前文章中已经说过了,所以你可以通过以下链接去看我之前的文章,错误截图只有web自动化测试才会有哦
https://www.cnblogs.com/linuxchao/p/linuxchao-pytest-report.html
https://www.cnblogs.com/linuxchao/p/linuxchao-pytest-Actual.html
完整的conftest.py代码
仅供参考
conftest.py
汉化报告
最后一步,汉化我们的测试报告,因为都是英文的,可能有的同学不太喜欢或者说领导不太喜欢,接下来就开始我们的汉化之路,汉化还是比较简单的, 只要小心谨慎即可
声明:以下修改的所有文件均存在pytest-html插件的源码目录下
修改plugin.py
plugin.py文件主要用来生成测试报告的html代码的,因此汉化肯定离不开修改这个文件了,接下来一步一步按照我的步骤修改吧(注释部分是源码,紧接着的是我修改后的代码)
# if len(log) == 0: # log = html.div(class_='empty log') # log.append('No log output captured.') if len(log) == 0: # modify by linux超log = html.div(class_='empty log')log.append('未捕获到日志') additional_html.append(log)
# head = html.head( # html.meta(charset='utf-8'), # html.title('Test Report'), # html_css) head = html.head( # modify by linux超html.meta(charset='utf-8'),html.title('测试报告'),html_css)
# outcomes = [Outcome('passed', self.passed), # Outcome('skipped', self.skipped), # Outcome('failed', self.failed), # Outcome('error', self.errors, label='errors'), # Outcome('xfailed', self.xfailed, # label='expected failures'), # Outcome('xpassed', self.xpassed, # label='unexpected passes')] outcomes = [Outcome('passed', self.passed, label="通过"),Outcome('skipped', self.skipped, label="跳过"),Outcome('failed', self.failed, label="失败"),Outcome('error', self.errors, label='错误'),Outcome('xfailed', self.xfailed,label='预期失败'),Outcome('xpassed', self.xpassed,label='预期通过')]
# if self.rerun is not None: # outcomes.append(Outcome('rerun', self.rerun)) if self.rerun is not None:outcomes.append(Outcome('重跑', self.rerun))# summary = [html.p( # '{0} tests ran in {1:.2f} seconds. '.format( # numtests, suite_time_delta)), # html.p('sfsf', # class_='filter', # hidden='true')] summary = [html.p( # modify by linux超'执行了{0}个测试用例, 历时:{1:.2f}秒 . '.format(numtests, suite_time_delta)),html.p('(取消)勾选复选框, 以便筛选测试结果',class_='filter',hidden='true')]
# cells = [ # html.th('Result', # class_='sortable result initial-sort', # col='result'), # html.th('Test', class_='sortable', col='name'), # html.th('Duration', class_='sortable numeric', col='duration'), # html.th('Links')]# modify by linux超 cells = [html.th('通过/失败',class_='sortable result initial-sort',col='result'),html.th('用例', class_='sortable', col='name'),html.th('耗时', class_='sortable numeric', col='duration'),html.th('链接')]
# results = [html.h2('Results'), html.table([html.thead( # html.tr(cells), # html.tr([ # html.th('No results found. Try to check the filters', # colspan=len(cells))], # id='not-found-message', hidden='true'), # id='results-table-head'), # self.test_logs], id='results-table')] results = [html.h2('测试结果'), html.table([html.thead( # modify by linux超html.tr(cells),html.tr([html.th('无测试结果, 试着选择其他测试结果条件',colspan=len(cells))],id='not-found-message', hidden='true'),id='results-table-head'),self.test_logs], id='results-table')]
#html.p('Report generated on {0} at {1} by '.format( html.p('生成报告时间{0} {1} Pytest-Html版本:'.format( # modify by linux超
# body.extend([html.h2('Summary')] + summary_prefix # + summary + summary_postfix) body.extend([html.h2('用例统计')] + summary_prefix # modify by linux超+ summary + summary_postfix)
# environment = [html.h2('Environment')] environment = [html.h2('测试环境')] # modify by linux超
plugin.py文件到这就修改完了,你可以生成报告查看以下效果,接下来修改main.js
修改main.js
/* function add_collapse() {// Add links for show/hide allvar resulttable = find('table#results-table');var showhideall = document.createElement("p");showhideall.innerHTML = '<a href="javascript:show_all_extras()">Show all details</a> / ' +'<a href="javascript:hide_all_extras()">Hide all details</a>';resulttable.parentElement.insertBefore(showhideall, resulttable); */ function add_collapse() { // modify by linux超// Add links for show/hide allvar resulttable = find('table#results-table');var showhideall = document.createElement("p");showhideall.innerHTML = '<a href="javascript:show_all_extras()">显示详情</a> / ' +'<a href="javascript:hide_all_extras()">隐藏详情</a>';resulttable.parentElement.insertBefore(showhideall, resulttable);
修改style.css
最后修改style.css,这个文件主要用来美化测试报告的,如果你对css比较熟悉,可以自定义报告样式
.expander::after {content: " (展开详情)";color: #BBB;font-style: italic;cursor: pointer; } .collapser::after {content: " (隐藏详情)";color: #BBB;font-style: italic;cursor: pointer; }
到目前为止,所有的汉化都已经完成了,接下来我们执行一下测试代码,查看一下报告的效果
最后报告效果
安装汉化版插件
为了方便大家使用,跳过修改源码过程,我已经把汉化版的pytest-html插件源码上传到了我的GitHub https://github.com/13691579846/pytest-html,下面说一下使用方法
方法1
1.如果你已经安装过了pytest-html,请先卸载 pip uninstall pytest-html
2.下载插件源码到本地,git clone https://github.com/13691579846/pytest-html 或者按照下图方法下载
3.打开CMD切换到插件中setup.py文件所在目录,执行如下命令
python setup.py install
方法2
1.如果你未安装过pytest-html插件,请先执行如下命令安装
pip install pytest-html
2.按照方法1的方式下载汉化后的插件,把下载后的插件中的部分分件覆盖到python第三方库目录下pytest-html下的部分文件
方法3
直接下载汉化后的源码,把源码中的pytest_html直接丢到python第三方库存放目录也可
方法4
最后一个方法就是按照我的文章步骤,一步一步修改自己的源码
方法5
下载pytest源码后使用pip install ./pytest-html 安装
这是我整理的《2024最新Python自动化测试全套教程》,以及配套的接口文档/项目实战【网盘资源】,需要的朋友可以下方视频的置顶评论获取。肯定会给你带来帮助和方向。
【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)
相关文章:

pytest-html报告修改与汉化
前言 Pytest框架可以使用两种测试报告,其中一种就是使用pytest-html插件生成的测试报告,但是报告中有一些信息没有什么用途或者显示的不太好看,还有一些我们想要在报告中展示的信息却没有,最近又有人问我pytest-html生成的报告&a…...

react-native从入门到实战系列教程一Swiper组件的使用及bug修复
轮播图,在app中随处可见,这么重要的功能我们怎么可能不学习下在react-native中的实现方式。 依然是第三方组件react-native-swiper 官网地址 https://www.npmjs.com/package/react-native-swiper 组件使用的组件及事件参考官方即可。 实现效果 官网…...
springboot开发的常用注解总结-配置组件类注解
Spring Boot 提供了许多注解,这些注解大大简化了 Spring 应用的配置和开发过程。以下是一些常见的 Spring Boot注解及其作用。 目录 配置组件类 (Configure Component )Configuration解释:Demo Code:更深度使用&#x…...
DataX 最新版本安装部署
1、下载 git clone gitgithub.com:alibaba/DataX.git 2、打包 mvn -U clean package assembly:assembly -Dmaven.test.skiptrue...

【架构】应用保护
这篇文章总结一下应用保护的手段。如今说到应用保护,更多的会想到阿里的sentinel,手段丰富,应用简单。sentinel的限流、降级、熔断,可以自己去试一下,sentinel主要通过配置实现功能,不难。sentinel的简介放…...

从核心到边界:六边形、洋葱与COLA架构的深度解析
文章目录 1 引言2 软件架构3 架构分类4 典型的应用架构4.1 分层架构4.2 CQRS4.3 六边形架构4.4 洋葱架构4.5 DDD 5 COLA架构设计5.1 分层设计5.2 扩展设计5.3 规范设计5.3.1 组件规范5.3.2 包规范5.3.3 命名规范 6 COLA架构总览7 小结 1 引言 软件的首要技术使命:管…...

04-Fastjson反序列化漏洞
免责声明 本文仅限于学习讨论与技术知识的分享,不得违反当地国家的法律法规。对于传播、利用文章中提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本文作者不为此承担任何责任,一旦造成后果请自行承担&…...
ABC365(A-D)未补
A - Leap Year(模拟) 题意:给定一个数字n,如果n不是4的倍数,输出365;如果n是4的倍数但不是100的倍数,输出366;如果n是100的倍数但不是400的倍数,输出365;如果…...
Python用png生成不同尺寸的图标
Kimi生成 from PIL import Imagedef generate_icon(source_image_path, output_image_path, size):with Image.open(source_image_path) as img:# 转换图片为RGBA模式,确保有透明通道if img.mode ! RGBA:img img.convert(RGBA)# 调整图片大小到指定尺寸img img.r…...

1688中国站获得工厂档案信息 API
公共参数 名称类型必须描述keyString是免费申请调用key(必须以GET方式拼接在URL中)secretString是调用密钥api_nameString是API接口名称(包括在请求地址中)[item_search,item_get,item_search_shop等]cacheString否[yes,no]默认y…...

定时任务框架 xxl-job
🍓 简介:java系列技术分享(👉持续更新中…🔥) 🍓 初衷:一起学习、一起进步、坚持不懈 🍓 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正🙏 🍓 希望这篇文章对你有所帮助,欢…...

C/C++关键字大全
目录 一、const 二、static 三、#define 和 typedef 四、#define 和 inline 五、#define 和 const 六、new 和 malloc 七、const 和 constexpr 八、volatile 九、extern 十、前置 和后置 十一、atomic 十二、struct 和 class 一、const 1、const 关键字可用于定义…...

ROS2 Linux Mint 22 安装教程
前言: 本教程在Linux系统上使用。 一、linux安装 移动硬盘安装linux:[LinuxToGo教程]把ubuntu装进移动固态,随时随用以下是我建议安装linux mint版本的清单: 图吧工具箱:https://www.tbtool.cn/linux mint: https://…...

快速将网站从HTTP升级为HTTPS
在当今数字化的世界中,网络安全变的越来越重要,HTTPS(超文本传输安全协议)不仅能够提供加密的数据传输,还能增强用户信任度,提升搜索引擎排名,为网站带来多重益处。所以将网站从HTTP升级到HTTPS…...

Qt程序移植至Arm开发板
目录 1.工具准备: 系统调试工具SecureCRT 虚拟机安装linux(Ubuntu) 交叉编译工具链 ARM 端Qt 环境(Qt-5.7.1) 1) linux processor SD安装 2)交叉编译工具链配置 2.编译Qt工程: 2.0 交叉编译 依赖库源码,生成动…...

删除分区 全局索引 drop partition global index Statistics变化
1.不一定unusable,可以先删除data (index 再删除过程中会更新结构)再drop/truncate. ---------------------- CREATE TABLE interval_sale ( prod_id NUMBER(6) , cust_id NUMBER , time_id DATE ) PARTITION BY RANGE (time_i…...

git回退未commit、回退已commit、回退已push、合并某一次commit到另一个分支
文章目录 1、git回退未commit2、git回退已commit3、git回退已push的代码3.1 直接丢弃某一次的push3.2 撤销push后,不丢弃改动,重新修改后要再次push 4、合并某一次commit到另一个分支 整理几个工作上遇到的git问题。 1、git回退未commit git回退未comm…...

yolov8pose 部署rknn(rk3588)、部署地平线Horizon、部署TensorRT,部署工程难度小、模型推理速度快,DFL放后处理中
特别说明:参考官方开源的yolov8代码、瑞芯微官方文档、地平线的官方文档,如有侵权告知删,谢谢。 模型和完整仿真测试代码,放在github上参考链接 模型和代码。 之前写了yolov8、yolov8seg、yolov8obb 的 DFL 放在模型中和放在后处理…...
程序员找工作之操作系统面试题总结分析
程序员在找工作面试时,操作系统方面可能会被问到的问题涵盖了多个核心知识点和概念。以下是对这些面试问题的总结和分析: 1. 核心硬件与体系结构 微机的核心部件:询问微机硬件系统中最核心的部件是什么(CPU)。处理机…...
TypeScript 迭代器和生成器详解
目录 迭代器(Iterators) 生成器(Generators) 使用场景 for..of vs. for..in 语句 for..of 循环 for..in 循环 区别总结 注意事项 总结 在 TypeScript 中,迭代器(Iterators)和生成器&am…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...

Qemu arm操作系统开发环境
使用qemu虚拟arm硬件比较合适。 步骤如下: 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载,下载地址:https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...

沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...