DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

pytest 的 JUnit 报告把 emoji 写成井号转义,修正 Unicode 范围

pytest 的 JUnit 过滤误写 Unicode 范围时会替换合法 emoji,应采用补充平面修复并核对生成报告中的原文字。

测试参数或失败信息包含 😀,终端看着正常,JUnit XML 中却变成 #x1F600;扩展汉字也变成类似 #x20000,可以检查 pytest 的合法 XML 字符过滤。文件本身可能仍能解析,只是原来的文字已经被替换了,给 CI 定位测试带来歧义。

旧正则把补充平面的范围写成 \u10000-\u10ffff。Python 的小写 \u 只读取四位十六进制数字,所以它并不表示 U+10000 到 U+10FFFF;合法范围没有包含那些字符,过滤器便将其按非法字符替换。

pytest 9.1.1 包含修复,使用八位的 \U 转义表示这个范围。它保留合法补充平面字符,也继续处理 XML 不允许的控制字符,不需要关闭整个 XML 安全过滤。

python -m pip install "pytest==9.1.1"

可用一条故意失败、消息带 emoji 与扩展汉字的测试,验证实际报告入口:

def test_report_unicode():
    raise AssertionError("unicode probe: 😀 𠀀")
python -m pytest --junitxml=unicode-report.xml test_report_unicode.py

测试失败退出是预期结果;随后解析报告,并核对失败节点中的原文字:

import xml.etree.ElementTree as ET

root = ET.parse("unicode-report.xml").getroot()
failures = root.findall(".//failure")
assert failures
text = "\n".join(
    (node.text or "") + node.get("message", "")
    for node in failures
)
assert "😀" in text and "𠀀" in text
assert "#x1F600" not in text and "#x20000" not in text

再检查 CI 上传的是刚生成的文件,并查看平台上的失败消息。XML 文件恢复原字符后,平台字体、字符显示或报告归档仍可能影响最终页面,不能把平台缺字都算成 pytest 的过滤问题。

不要在产物上批量把 #x... 替换回字符。业务消息本来就可能包含这个字面文本,而且原过滤也会处理真正非法的字符;全局反替换容易改坏其他内容。应由包含修复的 pytest 重新生成报告,并保留原文件作对照。

这项修复针对 Unicode 范围写错后的合法字符分类。XML 标记结构、属性转义、文件解码及其他插件生成的报告,都还需要各自验证;一个成功的 emoji 样例不代表所有报告字段都已经全面兼容。