pytest中文乱码本质是编码不一致导致的显示异常,需从源文件utf-8保存与声明、运行环境(如windows设pythonioencoding=utf-8)、插件写入逻辑(如pytest-html的write_text加encoding='utf-8')三处统一解决。

Pytest 中的中文乱码不是“报错”,而是输出或保存时编码不一致导致的显示异常,pytest 本身不会因中文抛出 SyntaxError 或 UnicodeDecodeError(除非源文件本身保存为非 UTF-8 编码且未声明)。真正要强制 UTF-8,得从三处下手:源文件、运行环境、插件写入逻辑。
确保测试文件以 UTF-8 保存且声明编码
这是最基础但常被跳过的一步。即使你写了中文 ids 或 docstring,如果文件实际是 GBK 编码保存的,Python 解释器读取时就会失败。
- 用 VS Code / PyCharm 打开测试文件,右下角查看当前编码,点击切换为
UTF-8,并选择「通过编码重新打开」 - 在文件首行添加 PEP 263 声明:
# -*- coding: utf-8 -*-(虽然 Python 3 默认 UTF-8,但显式声明能避免某些编辑器/IDE 误判) - 不要依赖记事本保存——它默认用 GBK,极易埋雷
设置运行时环境编码(Windows 尤其关键)
Windows 控制台默认使用 cp936(GBK),pytest 捕获 stdout/stderr 时若未指定编码,就可能把 UTF-8 字节流按 GBK 解码,造成双重乱码(如 å个)。
- 运行前临时设置:
set PYTHONIOENCODING=utf-8(Windows CMD)或$env:PYTHONIOENCODING="utf-8"(PowerShell) - 更稳妥的是在
pytest.ini中加:[pytest] addopts = --tb=short python_files = test_*.py # 强制输出编码 console_output_style = utf-8
(注意:console_output_style是 pytest 7.0+ 支持的选项;旧版本可改用--outputencoding=utf-8,但该参数在 7.0 后已弃用) - CI 环境(如 Jenkins)需在构建步骤中显式设置环境变量,不能只靠本地终端
修复 pytest-html 的 write_text 编码硬编码
pytest-html 3.2.0 及之前版本在 Windows 下默认用系统编码(GBK)写文件,self.logfile.write_text(...) 不带 encoding 参数,直接导致 HTML 文件头部是 UTF-8 内容、但文件本身是 GBK 编码,浏览器解析失败。
- 找到插件路径:
python -c "import pytest_html; print(pytest_html.__file__)",定位到html_report.py - 搜索
_save_report方法,在所有write_text调用后加encoding='utf-8':self.logfile.write_text(report_content, encoding='utf-8') style_path.write_text(self.style_css, encoding='utf-8')
- 同理检查
result.py中涉及字符串拼接生成nodeid或name的地方,避免先 encode('utf-8') 再 decode('unicode_escape') 这类多余转换——这会把原本正常的中文变成u82f9u679c
conftest.py 钩子中慎用 encode/decode 链式操作
网上流传的 item.name.encode().decode('unicode_escape') 是典型“以毒攻毒”:它假设原始字符串已是 Unicode 转义形式,但实际多数情况是正常中文字符串。强行 decode 会抛 UnicodeDecodeError 或静默损坏。
- 先判断是否含
u转义:if '\u' in item.name:再做解码 - 更安全的做法是只处理
nodeid中明确被转义的部分,例如:if '[' in item.nodeid and ']' in item.nodeid: parts = item.nodeid.split('[', 1) if len(parts) == 2: id_part = parts[1].rstrip(']') try: item._nodeid = f"{parts[0]}[{id_part.encode().decode('unicode_escape')}]" except UnicodeDecodeError: pass - 真正一劳永逸的方式是禁用 ID 转义:
disable_test_id_escaping_and_forfeit_all_rights_to_community_support=True加进pytest.ini,前提是你确认所有执行环境都支持 UTF-8 终端显示
最关键的其实是顺序:先保证源文件是 UTF-8,再统一运行时环境编码,最后才动插件和钩子。很多人一上来就改 conftest.py,结果发现控制台还是乱码——那说明根本没走到钩子那步,问题早在读取文件时就发生了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











