资讯详情

资讯详情

MR 里测试摘要空白、覆盖率不显示?JUnit 与覆盖率配置 9 步排查

本文环境组件版本 / 说明极狐GitLab17.0 及以上JihuLab.com 与私有化部署均适用Runner 执行器Docker示例语言Go 1.22、Node.js 20关键关键字artifacts:reports:junit、coverage、artifacts:reports:coverage_report一、先说现象三种最常见的配了但不显示现象 A流水线跑完了测试也执行了合并请求里的「测试摘要」面板是空的鼠标点开只显示显示详情后依旧没有条目。现象 B流水线作业列表里某个作业名称旁边出现一个解析错误指示符鼠标悬停提示 JUnit XML 解析错误。现象 C合并请求小部件里根本没有覆盖率百分比而流水线日志里明明打印了coverage: 82.5% of statements这类输出。这三个现象的根因完全不同A 多半是产物过期或超出体积限制B 是 XML 本身格式有问题C 是正则没匹配上。不要一上来就改测试框架先按下面的顺序定位。二、定位JUnit 报告与覆盖率报告是两套东西这是最容易踩的第一个坑官方文档的表述很直接覆盖率报告与覆盖率可视化读取不同的输入、产生不同的输出并且不共享配置配置其中一种并不会启用另一种。你想要的效果应该配置输入来源MR 小部件里的覆盖率百分比coverage正则作业日志中匹配到的第一个数字流水线/作业列表的覆盖率coverage正则同上MR 差异里的逐行注释artifacts:reports:coverage_reportCobertura 或 JaCoCo XML 产物覆盖率徽章、CSV 导出、历史图表coverage正则同上Coverage-Check 审批规则专业版及以上coverage正则同上踩坑 1只配了artifacts:reports:coverage_report然后到处找为什么 MR 上没有百分比。逐行注释来自 XML 报告百分比来自日志正则两者不是一回事想同时拿到就必须两个关键字都配。还有一个容易被忽略的差异coverage不记录子流水线的数据而coverage_report会记录。如果你的测试跑在子流水线里就别指望coverage给出百分比。三、九步排查与根治步骤 1确认测试框架输出的是 JUnit XML单元测试报告只认 JUnit XML 格式其他格式不会被解析。以 Go 为例需要先装转换工具# go-junit-report 把 go test 的输出转成 JUnit XML go install github.com/jstemmer/go-junit-report/v2latestgo-test: stage: test image: golang:1.22 script: - go test -v ./... 21 | go-junit-report -set-exit-code report.xml artifacts: when: always paths: - report.xml reports: junit: report.xml-set-exit-code很关键JUnit 报告本身不会影响作业状态要让测试失败时作业真的失败脚本必须以非零状态退出。步骤 2检查junit路径写法是否踩了目录红线junit支持单文件名、glob 模式、数组以及它们的组合# 单文件 reports: junit: report.xml # glob 模式 reports: junit: test-results/**/*.xml # 数组 reports: junit: [rspec-1.xml, rspec-2.xml, rspec-3.xml] # 组合 reports: junit: [rspec.xml, test-results/TEST-*.xml]踩坑 2不支持目录写法。写成junit: test-results或junit: test-results/**都不会被识别必须落到具体文件名或文件匹配模式上。步骤 3确认文件体积没超限单个 JUnit 文件必须小于 30 MB作业内所有 JUnit 文件总和小于 100 MB。超限会导致报告解析不出来表现为面板空白。# 本地先自查体积 find . -name *.xml -exec ls -lh {} \; | awk {print $5, $9}步骤 4给报告产物设置合理的过期时间产物过期会让测试摘要面板变空官方文档明确把报告产物已过期列为首要原因。默认值偏短建议显式声明artifacts: when: always expire_in: 1 week paths: - report.xml reports: junit: report.xml踩坑 3只配reports:junit而不配paths报告可以被解析但无法在产物里浏览排查时看不到原始 XML只能反复跑流水线。两个都配上最省事。步骤 5确认目标分支有基线数据如果目标分支上从未跑过生成测试报告的流水线就没有可比较的基线合并请求里会完全看不到「测试摘要」面板。# 在默认分支上手动跑一次流水线补基线 git checkout main git commit --allow-empty -m chore: generate test report baseline git push步骤 6验证 XML 本身能被解析作业名旁出现解析错误指示符说明 XML 有格式问题。先把产物抓下来本地验一遍# 用 python 快速校验 XML 是否闭合、属性是否合法 python3 -c import xml.etree.ElementTree as ET,sys; ET.parse(sys.argv[1]); print(XML OK) report.xml# 常见错误未转义的特殊字符导致解析失败 grep -n report.xml | headJUnit XML 里被解析的元素其实很有限testcase的classname显示为套件名、name测试名、file文件路径、time执行时间以及failure/error/skipped的元素内容。testsuite上的tests、failures、errors、timestamp属性不会被解析别指望靠它们显示总数。步骤 7检查是否存在重复的测试名称如果 XML 里有重名测试只有第一条会被采用其余被忽略表现为结果比预期少。# 统计重复的 testcase 名称 grep -o name[^]* report.xml | sort | uniq -c | sort -rn | head步骤 8配coverage正则让百分比显示出来coverage关键字的值是一个正则极狐GitLab 会扫描作业日志提取第一个匹配到的数字并存储。go-test: stage: test image: golang:1.22 script: - go test -coverprofilecoverage.out ./... - go tool cover -funccoverage.out | tail -1 coverage: /total:\s\(statements\)\s\d\.\d%/ artifacts: paths: - coverage.out踩坑 4正则里必须能匹配到你日志里真实出现的那行。go tool cover -func最后一行输出是total: (statements) 82.5%正则写成/coverage: \d%/就永远匹配不上MR 上自然没有百分比。改正则前先在日志里grep一遍确认文本。Node.js 侧同理jest-test: stage: test image: node:20 script: - npm ci - npx jest --coverage --coverageReporterstext-summary --coverageReporterscobertura coverage: /All files[^|]*\|\s*[\d.]/ artifacts: when: always paths: - reports/ reports: junit: reports/junit.xml coverage_report: coverage_format: cobertura path: reports/cobertura-coverage.xml步骤 9配coverage_report让 MR 差异出现逐行注释artifacts: reports: coverage_report: coverage_format: cobertura path: reports/cobertura-coverage.xml逐行注释只出现在合并请求差异中发生变更的文件上——没改动的文件即使报告里有覆盖率数据也不会被注释。这是设计如此不是配置错误。踩坑 5coverage与coverage_report可能给出不一致的数字。小部件的百分比来自日志正则注释来自 XML 报告。必须从同一次测试运行中生成两者否则你在看两份不同基准的数据。四、验证结果配置完成前后对比检查项配置前配置后MR 测试摘要面板空白或缺失展示新增/既有/已解决失败分类作业列表覆盖率无显示百分比及与目标分支差值MR 差异行级注释无变更文件显示 covered/missed失败测试定位翻作业日志面板内直接查看详情与截图Coverage-Check 审批不可用覆盖率下降时自动要求审批专业版及以上一个额外收益对于过去 14 天内在默认分支上失败的测试面板会提示Failed {n} time(s) in {default_branch} in the last 14 days一眼能看出这是偶发还是长期顽疾。五、给失败测试配上截图在 JUnit XML 的system-out里加附件标签路径相对于$CI_PROJECT_DIRtestcase time1.00 nameTestLogin system-out[[ATTACHMENT|/path/to/some/file]]/system-out /testcase同时把截图目录作为产物上传artifacts: when: always paths: - report.xml - screenshots/六、写在最后配测试报告和覆盖率九成的坑不在测试框架而在产物路径、体积限制、正则匹配这三处。按上面的顺序排查基本不需要碰测试代码。文中用到的完整.gitlab-ci.yml模板Go 与 Node.js 两份、正则速查表我整理成了一份清单需要的同学在评论区留个「覆盖率」或者到我主页置顶动态里自取脚本和模板都放那儿了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →