
本文介绍如何使用 pytest 精确验证学生编写的 python 函数是否按预期输出指定字符串(如 `print("hello world")`),核心是捕获标准输出并进行断言,避免常见误区(如直接比较函数对象)。
在教学场景中,你需要自动化验证学生是否准确实现了给定功能——例如,要求他们补全 print1() 函数,使其执行后在控制台输出 "Hello world"(注意:不是返回该字符串,而是调用 print() 产生标准输出)。此时,不能像检查返回值那样直接 assert print1() == "Hello world",因为 print() 默认返回 None;也不能写 assert print1 is "Hello world"(这是比较函数对象与字符串,语法和逻辑均错误)。
正确做法是:捕获函数执行时的实际 stdout 输出内容,并与期望字符串比对。Python 标准库提供了轻量可靠的工具——contextlib.redirect_stdout 配合 io.StringIO,可在测试中临时重定向 print() 的输出目标。
✅ 正确的 pytest 测试示例:
import io
import contextlib
def test_print1():
# 创建一个 StringIO 对象用于捕获输出
with contextlib.redirect_stdout(io.StringIO()) as captured:
print1() # 执行学生代码
# 断言捕获到的输出(注意:print() 会自动换行,所以实际输出是 "Hello world\n")
assert captured.getvalue() == "Hello world\n"⚠️ 注意事项:
- print() 默认末尾添加换行符 \n,因此期望值必须包含 \n,否则断言失败;
- 若需忽略换行差异(如兼容不同平台或简化教学),可用 assert captured.getvalue().strip() == "Hello world";
- 确保测试文件能正确导入 main.py 中的 print1 函数(推荐将 main.py 放在可导入路径下,或使用 pytest 的 --import-mode=importlib);
- 此方法仅捕获 print() 输出,不干扰其他 sys.stdout 操作,安全隔离。
? 进阶提示:对于多行输出、格式化字符串或含变量的练习,可结合参数化测试(@pytest.mark.parametrize)批量验证多个用例,大幅提升批改效率。这套模式可无缝扩展至 input() 模拟、异常检测等更复杂教学验证场景。











