断言表达式:从布尔到复合条件

写断言这事儿,说白了就是写表达式。你想想看,我们每天在代码里写的 if 判断、while 条件,本质上都是布尔表达式。断言也一样——它就是一个必须为真的条件。今天咱们就聊聊怎么把断言写得既精准又优雅。

布尔表达式:最基础的断言

最简单的断言,就是一个布尔值。比如:

assert result == expected
assert user.is_active
assert len(items) > 0

这些一眼就能看懂。但我个人习惯,不会只写一个布尔表达式就完事。为什么呢?因为当断言失败时,你只能看到「AssertionError」,完全不知道哪里出了问题。

我的小技巧: 给布尔断言加个描述信息。比如 assert result == expected, f"期望 {expected},实际得到 {result}"。这样失败时一眼就知道差距在哪。

我在项目中遇到过这样一个坑:有个同事写了个断言 assert status_code == 200,结果某天接口返回了 500,他排查了半天才发现是服务端挂了。要是当时加个描述信息,几秒钟就能定位问题。

复合条件断言:and 的妙用

很多时候,一个条件不够。你需要同时满足多个条件。这时候 and 就派上用场了。

# 检查用户是否有效且已登录
assert user.is_active and user.is_authenticated

# 检查数值范围
assert 0 <= score and score <= 100

# 检查多个字段
assert response.status_code == 200 and response.json().get("success") is True

嗯,这里要注意:and 是短路运算符。如果第一个条件为 False,第二个条件根本不会执行。这在某些场景下能救命——比如先检查对象不为空,再访问它的属性。

我曾经踩过的坑: 写了个 assert data is not None and data["key"] == "value"。当时觉得没问题,结果 data 为 None 时,第二个条件直接抛 AttributeError,断言还没执行就崩了。后来我改成先判断再断言,或者用 try-except 兜底。

复合条件断言:or 的灵活运用

or 用来表达「至少满足一个条件」。这在测试中很常见,比如一个接口可能返回多种合法状态码。

# 成功状态码可以是 200 或 201
assert status_code == 200 or status_code == 201

# 用户可以是管理员或超级用户
assert user.role == "admin" or user.role == "superuser"

# 数据可能来自缓存或数据库
assert cached_data is not None or db_data is not None

你想想看,如果不用 or,你得写两个断言,或者用 if-else 绕一圈。多麻烦。

复合条件断言:not 的反向思维

not 用来取反。有时候「不是什么」比「是什么」更容易表达。

# 用户不能是游客
assert not user.is_guest

# 列表不能为空
assert not len(items) == 0

# 状态不能是错误
assert not status.startswith("5")

我个人习惯,能用正向表达就用正向。比如 assert len(items) > 0 比 assert not len(items) == 0 更直观。但有些场景下,取反确实更自然——比如检查某个标志位没有被设置。

组合使用:and/or/not 的实战

真正复杂的场景,需要把这三个运算符组合起来。这时候括号就很重要了——别省括号,省了括号就是给自己挖坑。

# 用户必须已登录,且角色是管理员或编辑
assert user.is_authenticated and (user.role == "admin" or user.role == "editor")

# 数据必须存在,且不能是空字符串或 None
assert data is not None and not (data == "" or data is None)

# 请求必须成功,且返回的数据不能为空
assert response.ok and not (response.json() is None or len(response.json()) == 0)
核心原则: 用括号明确优先级。虽然 Python 的运算符优先级有明确规则,但写代码是给人看的。加括号能让读代码的人一眼看懂你的意图,不用去查优先级表。

我在项目中遇到过最离谱的一次:有个同事写了 assert a or b and c,结果 and 优先级高于 or,实际执行的是 assert a or (b and c),跟他想的完全不一样。排查了半小时才发现是优先级问题。

用 SVG 梳理知识体系

下面这张图,把断言表达式的核心逻辑串起来了:

断言表达式知识体系 断言表达式 布尔表达式 直接判断 True/False 建议加描述信息 复合条件断言 and(且) 短路特性 or(或) 至少一个成立 not(取反) 反向思维表达 优先用正向表达 核心原则:用括号明确优先级 组合使用时,括号比运算符优先级更可靠

实战中的避坑指南

说了这么多,最后分享几个我踩过的坑:

  • 别滥用 not: 我曾经写了个 assert not not flag,被同事笑了半天。双重取反等于没取反,直接写 assert flag 不香吗?
  • 注意 and/or 的短路行为: 如果第二个条件有副作用(比如修改全局变量),短路可能导致意想不到的结果。我建议断言里不要写有副作用的表达式。
  • 复杂条件拆开写: 如果一个断言里用了三个以上的 and/or,我建议拆成多个断言。这样失败时能精确知道是哪个条件不满足。
我的个人习惯: 一个断言里最多用两个逻辑运算符。超过这个数,就拆成多个断言,或者用变量把中间结果存起来。代码是写给人看的,不是写给机器看的。

好了,关于断言表达式就聊到这儿。记住:布尔表达式是基础,复合条件让断言更灵活,但别忘了加括号和描述信息。下次写断言时,多想想「如果这个断言失败了,我能一眼看出问题在哪吗?」


可可精品资料库