assert 不是函数,而是 Python 语句/关键字 ;
写法像函数,其实更像"if not ...: raise AssertionError" 的语法糖。
记住一句话:"assert 后面只认一个布尔表达式,失败时把逗号后的值当成错误信息扔出去。"
1️⃣ 基本形式
Python
复制
assert <布尔表达式> [, 错误信息]
-
布尔值为 True → 什么都不发生,继续往下跑。
-
布尔值为 False → 立即抛
AssertionError,整个程序中断(除非外层有 try)。 -
错误信息可以是任意对象;Python 会把
AssertionError(<错误信息>)原样实例化给你看。
2️⃣ 参数拆解(伪参数)
表格
复制
| 位置 | 官方叫法 | 说明 | 是否必须 |
|---|---|---|---|
| 第 1 段 | test expression | 任何能当条件判断的表达式 | ✅ |
| 第 2 段 | message(逗号后面所有) | 失败时要带走的额外信息 | ❌ |
注意:
-
逗号后面可以写任意表达式、任意数量 ,Python 会把它们先求值 再打包成 tuple 当成一个整体 message。
-
因此常利用"副作用"做抢救:截图、停服务、睡几秒......只要写在 tuple 里,失败时就会被执行。
3️⃣ 运行期行为(字节码层面)
Python
复制
assert expr, msg
等价于
Python
复制
if __debug__: # Python 默认 True;加 -O 或 -OO 会变成 False
if not expr:
raise AssertionError(msg)
⇒ 生产环境若用 python -O xxx.py,所有 assert 会被直接抹掉,所以别把真正业务逻辑写进 assert 表达式里!
4️⃣ 常见误区
❌ assert 1 == 1, logger.error("ok")
成功时也会执行 logger.error → 用 tuple 包起来才安全:
✅ assert 1 == 1, (logger.error("ok"),) ← 失败才执行
❌ 把数据写入、文件删除写在 assert 表达式本身
一旦别人 python -O 运行,你的"清理"代码就消失了 → 用普通 if/raise 或 try/finally。
5️⃣ 在 pytest 里的特殊含义
-
pytest 用 AssertionError 当"测试失败"信号;
-
只要 assert 失败,pytest 就会:
1. 捕获 AssertionError
2. 把本地变量值反向解析成"友好提示"
3. 把退出码设为 1,让 Jenkins 标红
-
因此写 UI/接口自动化时,断言点就是"检查点",一个用例里可以有多个 assert。
6️⃣ 一张表速记
表格
复制
| 场景 | 推荐写法 |
|---|---|
| 单元测试、检查点 | assert 实际 == 预期 |
| 需要失败 info | assert x, f"期望 200,实际 {x}" |
| 失败时要"抢救" | assert x, (截图(), 恢复环境(), 日志()) |
| 生产环境校验 | 用 if not x: raise ValueError(...),不要用 assert |
一句话总结
assert 就是 "断定" 的快捷键:
True 当没看见,False 立刻扔 AssertionError,并把逗号后的值当作案发现场证据。