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 样例不代表所有报告字段都已经全面兼容。


