pytest默认不显示断言失败的具体行号和变量值,需用-vv、--tb=short/long控制堆栈深度,--show-capture=all显示print/logging输出;mock路径须匹配导入位置而非定义位置;assert应直接写表达式以启用pytest智能diff;环境差异、浮点比较、异步测试等需针对性处理。

pytest 报错但没显示具体哪行失败
默认情况下 pytest 遇到断言失败只打印异常类型和简短消息,比如 AssertionError,不带堆栈或变量值,根本看不出是哪个 assert 没过、变量实际是什么。
加 -v 只能多显示测试名,真正有用的是 -vv(双 v)或直接用 --tb=short / --tb=long 控制 traceback 深度。更实用的是 --show-capture=all,它会把 print()、logging 输出也一并打出来——很多测试逻辑里其实埋了调试输出,只是默认被截断了。
-
pytest test_example.py::test_something -vv --show-capture=all是日常定位首选组合 - 如果用了
pytest.raises(...)但报错说“未捕获异常”,大概率是with块里根本没触发预期异常,或者异常类型写错了(比如写了ValueError实际抛出TypeError) - 注意
pytest默认跳过stdout捕获,print()在测试里不会自动显示,必须显式加--show-capture
测试里调用的函数实际没执行
常见于 mock 使用不当:比如用了 patch 但路径写错,导致原函数照常运行,而你却在检查 mock 对象的调用次数——当然为 0。
mock 的路径必须是「被测试代码中导入的位置」,不是函数定义的位置。例如你在 app.py 里写了 from utils import fetch_data,然后在 app.py 的某个函数里调用了 fetch_data(),那 patch 就得写成 @patch("app.fetch_data"),而不是 @patch("utils.fetch_data")。
立即学习“Python免费学习笔记(深入)”;
- 最稳的办法是打开测试文件,在对应函数里加一行
print(fetch_data),运行看输出——如果是<magicmock ...></magicmock>说明 patch 成功;如果是真实函数地址,说明 patch 路径错了 - 用
side_effect替代return_value更容易发现问题:比如side_effect=lambda x: print("called with", x) or "fake",至少能确认是否真被调了 - 避免在测试类外全局 patch,容易漏掉 scope 或覆盖其他测试;优先用函数参数形式:
def test_xxx(mock_fetch):
AssertionError 提示信息太模糊,比如 “False is not true”
Python 内置 assert 不带消息时,只报布尔结果,完全看不出上下文。别依赖它裸奔。
要么手动加描述字符串:assert result == expected, f"expected {expected}, got {result}";要么直接用 pytest 推荐的 assert 风格——它自带智能 diff,对列表、字典、字符串都自动展开对比。但前提是别提前把表达式包进变量里。
- ❌ 错误写法:
is_ok = user.is_active();assert is_ok→ 只报False is not true - ✅ 正确写法:
assert user.is_active() is True→ pytest 能推导出左边是False,右边是True - 对复杂结构,用
assert response.json() == {"status": "ok"},pytest 会逐字段标红差异,比手写字符串拼接清晰得多 - 如果必须用自定义校验逻辑,就用
pytest.fail(f"详细原因:..."),别省那几行
CI 上通过、本地失败,或反过来
八成是环境差异:Python 版本、依赖版本、时区、文件路径分隔符、浮点数精度、随机种子,甚至临时目录权限。
先查 pytest --version 和 pip list,重点核对 pytest、numpy、pydantic 这类对行为敏感的包。再看测试里有没有硬编码路径("./data/test.csv"),应该用 Path(__file__).parent / "data" / "test.csv"。
- 时间相关测试务必用
freezegun固定时间,别信datetime.now()的“稳定” - 浮点比较永远用
math.isclose(a, b)或pytest.approx(),别用== - 随机性测试(如
random.shuffle)开头加random.seed(42),不然每次跑结果不同 - CI 日志里搜
WARNING,有些库在新版本会静默降级行为(比如requests对无效 SSL 证书的处理)
最难缠的是异步测试里混了同步断言,或者 fixture 里用了 yield 但 teardown 部分抛错被吞掉——这种得开 --full-trace 看完整堆栈,不能只盯最后一行。










