pytest默认捕获stdout/stderr以避免干扰日志,需用capsys fixture调用readouterr()获取字符串输出,注意换行符、区分.out/.err,跨测试不复用;capfd用于C层或子进程输出。

为什么 print() 输出在 pytest 里默认不显示也不易断言
因为 pytest 默认捕获所有 stdout 和 stderr,既不让它们刷到终端(避免干扰测试日志),也不直接暴露给断言逻辑。你写 print("hello"),控制台看不到,assert "hello" in output 也根本没地方取 —— 这不是 bug,是设计,但得知道怎么解。
关键点:pytest 提供的 capsys fixture 就是专干这事的,它在测试函数执行前后自动接管标准输出流,提供干净、可查的捕获结果。
-
capsys.readouterr()必须在被测代码执行「之后」调用,否则拿到的是空的out和err - 它捕获的是字符串,不是字节;中文、换行符
\n都原样保留,注意末尾是否有换行(print("x")自带 \n,print("x", end="")不带) - 不能跨测试复用同一个
capsys实例 —— pytest 每个测试函数都注入新实例,这是隔离保障,别试图缓存它
capsys.readouterr() 返回值结构和常见误读
capsys.readouterr() 返回一个命名元组 CaptureResult,带两个属性:.out(标准输出)和 .err(标准错误)。新手常以为它是 dict 或字符串,直接 assert "xxx" in capsys 报 TypeError: argument of type 'Capsys' is not iterable。
- 必须显式调用
readouterr(),不能直接对capsys做 in / assert -
.out是str,但含换行符;比如print(123)→"123\n",断言时写assert "123" in out可以,但assert out == "123"会失败 - 如果函数同时写了
print()和logging.error(),后者默认走stderr,得查.err,不是.out
示例:
立即学习“Python免费学习笔记(深入)”;
def test_print_output(capsys):
print("start")
print(42)
captured = capsys.readouterr()
assert captured.out == "start\n42\n" # ✅ 精确匹配(含换行)
assert "42" in captured.out # ✅ 模糊匹配
assert captured.err == "" # ✅ 确保没 stderrcapsys 与 capfd 的核心区别:什么时候该换用 capfd
capsys 拦截的是 Python 层面的 sys.stdout / sys.stderr,对纯 C 扩展或子进程输出无效;capfd 则直接操作文件描述符(fd 1 和 2),能捕获更底层的输出,比如用 os.system("echo hi") 或某些 C 库打印的内容。
- 95% 的普通
print()、sys.stdout.write()场景,用capsys足够,且更轻量、更安全 - 如果你的被测代码调用了
subprocess.run(..., capture_output=True)以外的外部命令,或者用了ctypes直接写 fd,capsys会漏掉,此时才考虑capfd -
capfd在 Windows 上偶尔有缓冲问题,且无法区分 Python 层和 C 层的输出来源,调试时更难定位源头
测试含多行、格式化或 ANSI 转义字符的输出
真实项目里 print() 常带缩进、颜色(如 \033[32mOK\033[0m)、甚至动态宽度(f"{x:)。这些内容会被原样捕获,但断言时容易因空格、颜色码失配。
- 用
repr(captured.out)查看真实内容,尤其怀疑有不可见字符时(比如" x\n"和"x\n"看起来一样) - 对 ANSI 颜色码,要么在断言中显式包含(
assert "\033[32mOK\033[0m" in captured.out),要么用第三方库如ansi2html或正则清洗后再比 - 避免用
.strip()全局处理 —— 它会吃掉有意义的缩进,比如测试日志前缀"[INFO] hello"中的空格可能正是格式要求
复杂输出建议拆成小断言:先确认关键词存在,再检查行数、是否含特定前缀等,比一行 == 更稳健。
真正难的不是捕获,是定义“什么才算正确输出”——比如带时间戳的 log,每次运行内容都不同,这时得用正则或只断言固定部分。这一步没法靠 fixture 自动解决,得人来判断边界。



















