pytest-check 是提供软断言能力的插件,本质区别在于:assert 是硬断言,失败即中断执行;而 pytest-check 的 check.xxx() 失败不中断,需显式调用 check.raise_errors() 才统一汇总报错。

pytest-check 是什么,它和 assert 有什么本质区别
pytest-check 不是替代 assert 的断言库,而是提供「软断言」能力的插件:即使某条检查失败,测试函数仍会继续执行,所有检查结果统一在最后汇总报错。这在需要一次性验证多个独立条件(比如 UI 页面多个字段值、API 响应多个字段)时特别实用——避免传统 assert 一错就停,反复运行才能发现全部问题。
- 软断言不中断执行,靠
check.equal()、check.is_true()等函数收集失败项 - 必须在测试函数末尾显式调用
check.raise_errors()才会真正抛出异常 - 它不是 pytest 内置功能,需额外安装:
pip install pytest-check - 不支持在
with语句或嵌套作用域中隐式触发;所有检查必须在同一个测试函数内完成
如何正确写一个带软断言的 pytest 测试函数
关键在于两步缺一不可:先调用各种 check.xxx(),再在函数末尾调用 check.raise_errors()。漏掉后者,测试永远“通过”,哪怕所有检查都失败。
import pytest_check as check
<p>def test_user_profile():
data = {"name": "Alice", "age": 30, "email": "alice@example.com"}</p><pre class='brush:python;toolbar:false;'>check.equal(data["name"], "Bob") # ❌ 失败,但继续
check.greater(data["age"], 25) # ✅ 通过
check.is_in("@example.com", data["email"]) # ✅ 通过
check.raise_errors() # ⚠️ 必须有!否则前面的失败被静默吞掉-
check.raise_errors()只抛一次异常,汇总所有失败项,错误信息里会列出每条失败的检查位置和预期/实际值 - 不要在循环里反复调用
check.raise_errors(),它只应在函数结尾调用一次 - 如果测试函数提前 return 或 raise 其他异常,
check.raise_errors()就不会执行,导致失败被忽略
常见报错和容易踩的坑
最典型的错误是忘记导入或拼错模块名,以及混淆软断言和硬断言的使用逻辑:
- 报错
ModuleNotFoundError: No module named 'pytest_check'→ 检查是否真的运行了pip install pytest-check(注意是下划线,不是短横线) - 测试始终显示 PASSED,但你知道某条检查该失败 → 99% 是漏了
check.raise_errors() - 在 fixture 中调用
check.xxx(),但 fixture 没有调用raise_errors()→ 软断言只在当前作用域生效,fixture 里的检查不会自动透传到测试函数 - 和
pytest.raises()混用:不能在with pytest.raises(...)块里用check.xxx()验证异常属性,因为异常已被捕获,后续代码不执行
什么时候不该用 pytest-check
软断言不是银弹。它适合「并行验证多个无关条件」,但会掩盖执行路径依赖关系:
立即学习“Python免费学习笔记(深入)”;
- 如果第二条检查依赖第一条的结果(比如先登录再查 dashboard),用软断言会让失败变得难以归因
- 单元测试强调单一职责,一个测试只该聚焦一个行为;塞进太多
check.xxx()往往说明测试本身职责过重 - CI 环境里,软断言失败的堆栈信息不如原生
assert清晰,排查时要多看汇总消息里的行号和上下文 - 它不支持自定义异常类或延迟断言超时控制,复杂校验逻辑建议封装成普通函数 + 显式
assert
真正要用好 pytest-check,得清楚它只是把「多个 assert 合并报错」这件事自动化了,而不是改变测试设计的基本原则。


















