当前位置: 首页 > news >正文

自动化测试报告优化:jenkins+jmeter定制化HTML报告生成

为什么需要定制化报告?

JMeter生成的HTML报告虽然功能完善,但关键信息不突出、展示不直观

如何实现

编写一个符合预期的shell脚本,在jenkins中通过shell步骤执行shell脚本来生成定制化html报告,后续可以通过归档至主节点,来进行展示等

shell脚本逻辑流程图:

在这里插入图片描述

shell脚本:

#!/bin/bash# 【配置区】与 Jenkins HTML Publisher 配置对齐
# 工作空间根路径
WORKSPACE="/work/jenkins/workspace/Automated-testing/AgentJmeter-PublicAgent-release"  # JMeter 相关路径
JMETER_JMX="$WORKSPACE/PublicAgent-release.jmx"       # 测试计划文件
JTL_FILE="$WORKSPACE/PublicAgent-release.jtl"  # JMeter 结果文件
HTML_REPORT_DIR="$WORKSPACE/html_report"  # JMeter 默认 HTML 报告输出目录  # 自定义报告路径(与 HTML Publisher 配置一致)
CUSTOM_REPORT_DIR="$WORKSPACE/result_html"  
CUSTOM_HTML="$CUSTOM_REPORT_DIR/resultTotal.html"  # 索引页:resultTotal.html  # JTL 文件字段列号(从 1 开始,与实际 JTL 表头严格对齐)
SUCCESS_COL=8        # success 字段所在列(第 8 列)
AGENT_NAME_COL=6     # 智能体名称所在列(threadName 列,第 6 列)
RESPONSE_MSG_COL=5   # responseMessage 字段所在列(第 5 列)
FAILURE_MSG_COL=9    # failureMessage 字段所在列(第 9 列)  # 成功/失败标识值
SUCCESS_VALUE="true"
FAILURE_VALUE="false"  # 【函数区】模块化封装核心逻辑
# 1. 日志打印函数(带时间戳,便于调试)
log() {echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}# 2. 清理旧文件/目录(健壮性处理:rm -rf 避免目录不存在报错)
clean_old_resources() {log "开始清理旧文件/目录..."rm -rf "$HTML_REPORT_DIR"/*   # 清理 JMeter 默认报告rm -rf "$JTL_FILE"            # 清理旧 JTL 文件rm -rf "$CUSTOM_REPORT_DIR"   # 强制删除自定义报告目录(无则忽略)mkdir -p "$CUSTOM_REPORT_DIR" # 重建自定义报告目录(确保父目录存在)log "旧文件/目录清理完成"
}# 3. 运行 JMeter 生成测试结果 + 默认 HTML 报告
run_jmeter_test() {log "开始运行 JMeter 测试..."jmeter -n -t "$JMETER_JMX" \-l "$JTL_FILE" \-e \-o "$HTML_REPORT_DIR"# 检查 JMeter 执行返回码(非 0 则失败)if [ $? -ne 0 ]; thenlog "× JMeter 执行失败,脚本终止"exit 1filog "JMeter 测试执行完成,JTL 和默认报告已生成"
}# 4. 解析 JTL 统计成功/失败数(处理多行字段)
parse_jtl_summary() {log "开始解析 JTL 统计成功/失败数..."# 使用 awk 解析 JTL,注意分隔符和引号处理local result=$(awk -v FPAT='([^,]*)|("[^"]*")' -v s_col="$SUCCESS_COL" -v s_val="$SUCCESS_VALUE" -v f_val="$FAILURE_VALUE" 'NR > 1 {gsub(/^"|"$/, "", $s_col);  # 移除字段前后引号(JTL 带引号时保留)if ($s_col == s_val) count_success++else if ($s_col == f_val) count_failure++}END {print count_success+0, count_failure+0  # 强制转数字,避免空值}' "$JTL_FILE")# 新增调试日志,查看 awk 输出log "DEBUG: awk 返回的 success/failure 数: [$result]"  # 按空格分割 awk 输出(awk 用 print 输出时默认空格分隔)IFS=' ' read -r SUCCESS_COUNT FAILURE_COUNT <<< "$result"  # 计算总数(此时 SUCCESS_COUNT/FAILURE_COUNT 应为纯数字)TOTAL_COUNT=$((SUCCESS_COUNT + FAILURE_COUNT))log "成功数: $SUCCESS_COUNT, 失败数: $FAILURE_COUNT, 总数: $TOTAL_COUNT"
}# 5. 计算成功率
calculate_success_rate() {log "计算成功率..."if [ "$TOTAL_COUNT" -eq 0 ]; thenSUCCESS_RATE="0.00"elseSUCCESS_RATE=$(awk -v s="$SUCCESS_COUNT" -v t="$TOTAL_COUNT" 'BEGIN { printf "%.2f", (s/t)*100 }')filog "成功率: $SUCCESS_RATE%"
}# 6. 提取失败详情
parse_failure_details() {awk -v FPAT='([^,]*)|("[^"]*")' -v s_col="$SUCCESS_COL" -v f_val="$FAILURE_VALUE" -v agent_col="$AGENT_NAME_COL" -v msg_col="$FAILURE_MSG_COL" 'NR == 1 { next }  # 跳过表头行{success_val = $s_col;gsub(/^"|"$/, "", success_val);if (success_val == f_val) {agent_name = $agent_col;gsub(/^"|"$/, "", agent_name);split(agent_name, parts, "^");failure_msg = $msg_col;gsub(/^"|"$/, "", failure_msg);gsub(/\n/, "<br>", failure_msg);gsub(/&/, "&amp;", failure_msg);gsub(/</, "&lt;", failure_msg);gsub(/>/, "&gt;", failure_msg);printf "<tr class=\"failure-row\"><td>%s</td><td>%s</td><td>%s</td></tr>\n", parts[1], parts[2], failure_msg;}}' "$JTL_FILE"
}# 7. 提取成功详情
parse_success_details() {awk -v FPAT='([^,]*)|("[^"]*")' -v s_col="$SUCCESS_COL" -v s_val="$SUCCESS_VALUE" -v agent_col="$AGENT_NAME_COL" -v msg_col="$RESPONSE_MSG_COL" 'NR == 1 { next }  # 跳过表头行{success_val = $s_col;gsub(/^"|"$/, "", success_val);if (success_val == s_val) {agent_name = $agent_col;gsub(/^"|"$/, "", agent_name);split(agent_name, parts, "^");response_msg = $msg_col;gsub(/^"|"$/, "", response_msg);gsub(/\n/, "<br>", response_msg);gsub(/&/, "&amp;", response_msg);gsub(/</, "&lt;", response_msg);gsub(/>/, "&gt;", response_msg);printf "<tr class=\"success-row\"><td>%s</td><td>%s</td><td>%s</td></tr>\n", parts[1], parts[2], response_msg;}}' "$JTL_FILE"
}# 8. 生成自定义 HTML 报告
generate_custom_report() {log "开始生成自定义报告: $CUSTOM_HTML"# 使用 HEREDOC 生成 HTML 内容,嵌入统计变量和详情cat <<EOF > "$CUSTOM_HTML"
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>执行结果统计</title><style># css样式body { font-family: Arial, sans-serif; padding: 20px; background-color: #f9f9f9; }h2 { color: #333; border-bottom: 2px solid #ddd; padding-bottom: 10px; }table { border-collapse: collapse; width: 90%; margin: 20px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.1); background-color: white; }th, td { padding: 12px; text-align: left; border: 1px solid #ddd; }th { background-color: #f2f2f2; color: #333; font-weight: bold; }.success-row { background-color: #d4f4dd; color: green; }.failure-row { background-color: #f8cccc; color: red; }.total-row { background-color: #e6e6fa; font-weight: bold; }.rate-row { background-color: #fffacd; }.details-table { width: 100%; }.details-table td, .details-table th { vertical-align: top; }pre { white-space: pre-wrap; word-wrap: break-word; background-color: #f0f0f0; padding: 10px; border: 1px solid #ccc; border-radius: 4px; }</style>
</head>
<body>
<h2>执行结果统计</h2>
<table><tr class="success-row"><th>统计项</th><th>统计值</th></tr><tr class="success-row"><td>成功数</td><td>$SUCCESS_COUNT</td></tr><tr class="failure-row"><td>失败数</td><td>$FAILURE_COUNT</td></tr><tr class="total-row"><td>总数</td><td>$TOTAL_COUNT</td></tr><tr class="rate-row"><td>成功率</td><td>$SUCCESS_RATE%</td></tr>
</table><h2>执行结果数据</h2>
<table class="details-table"><tr><th>智能体名称</th> <th>Query</th><th style="width:60%">详细信息</th> </tr>
$(parse_failure_details)$(parse_success_details)
</table>
</body>
</html>
EOF# 确保报告文件权限(Jenkins 可访问)chmod 644 "$CUSTOM_HTML"log "自定义报告生成完成:$CUSTOM_HTML"
}# 9. 检验报告文件是否生成
verify_report() {if [ -f "$CUSTOM_HTML" ]; thenlog "报告验证通过:$CUSTOM_HTML 存在"elselog "错误:$CUSTOM_HTML 生成失败"exit 1fi
}# 【主流程】按顺序执行函数
main() {clean_old_resourcesrun_jmeter_testparse_jtl_summarycalculate_success_rategenerate_custom_reportverify_report
}# 启动主流程
main

定制化html页面总览:

在这里插入图片描述

http://www.dtcms.com/a/270969.html

相关文章:

  • 【LeetCode】大厂面试算法真题回忆(102)--集五福
  • Java学习第二十七部分——bug检修
  • 前端接收流式数据demo,并用markdown解析数据,包括EventSource和fetch两种方式
  • LeetCode 138题解 | 随机链表的复制
  • 力扣 hot100 Day39
  • 【保姆级喂饭教程】Windows下安装Git Flow
  • 电网的智能觉醒——人工智能重构能源生态的技术革命与公平悖论
  • JAVA策略模式demo【设计模式系列】
  • 自动化Trae Apollo参数解释的批量获取
  • 苍穹外卖项目日记(day04)
  • ASP.NET Core 8 轻松配置Serilog日志
  • 智慧码头船舶网络部署5G工业路由器无人值守场景应用
  • 无人设备遥控器之双向通讯技术篇
  • 【机器人】Aether 多任务世界模型 | 4D动态重建 | 视频预测 | 视觉规划
  • C++并发编程-11. C++ 原子操作和内存模型
  • Linux驱动学习day20(pinctrl子系统驱动大全)
  • Ubuntu防火墙缺失问题(unit firewalld.service could not be found, ubuntu 22)
  • EFK9.0.3 windows搭建
  • Linux系统管理实战:生成大文件与定位磁盘挂载点
  • 专题:2025母婴行业洞察报告|附60+份报告PDF汇总下载
  • Linux中shell(外壳)和内核(kernel)的关系
  • Claude Code:终端上的 AI 编码助手,潜力与挑战并存
  • 从零用java实现 小红书 springboot vue uniapp(13)模仿抖音视频切换
  • 华为数通HCIA vs HCIP:新手入门选哪个更合适?
  • 利用sCMOS科学相机测量激光散射强度
  • Rk3568驱动开发_阻塞IO_15
  • SQL Server通过存储过程实现飞书消息卡片推送
  • Live555-RTSP服务器
  • nl2sql的解药pipe syntax
  • 【工具变量】上市公司企业金融强监管数据、资管新规数据(2001-2024年)