2. 断言基础

各位同学好,我是你们的测试架构师老K。今天咱们聊聊断言——这个听起来简单、但实际坑不少的话题。

断言是什么?说白了,就是你在代码里埋下的「检查点」。它帮你验证:程序运行到这里,状态对不对?结果符不符合预期?

我个人习惯把断言比作「代码里的质检员」。没有它,你的测试就像闭着眼睛开车——跑得再快也不知道方向对不对。

核心观点:断言是测试用例的灵魂。没有断言的测试,只是「执行了代码」,不是「验证了功能」。

一、assert语句详解

Python里的assert语句,语法极其简单:

assert 条件表达式, "失败时的提示信息"

就这么一行。但你别小看它。我在项目中见过太多人把assert用成了「摆设」。

举个例子:

def divide(a, b):
    assert b != 0, "除数不能为0"
    return a / b

# 正常调用
print(divide(10, 2))  # 输出 5.0

# 触发断言
print(divide(10, 0))  # AssertionError: 除数不能为0

嗯,这里要注意:assert一旦失败,程序会直接抛出AssertionError,后面的代码就不执行了。

我的经验:assert适合做「防御性检查」,比如参数校验、前置条件验证。但别用它来做业务逻辑判断——那会让你的代码在正式环境里「静默失效」。

二、断言表达式:怎么写才优雅?

断言表达式可以是任何返回布尔值的东西。但怎么写,是有讲究的。

常见写法:

# 直接比较
assert result == expected

# 使用in操作符
assert "error" in response.text

# 使用逻辑运算
assert len(data) > 0 and data[0]["status"] == "ok"

# 使用函数调用
assert is_valid_email(email)

我曾经踩过一个坑:在断言里写了复杂的表达式,结果断言失败时,根本看不出是哪个条件出了问题。

避坑指南:断言表达式尽量保持「单一职责」。一个断言只检查一件事。如果需要检查多个条件,拆成多个assert语句。

比如这样:

# ❌ 不推荐:失败后不知道是哪个条件不满足
assert user.age > 18 and user.status == "active" and user.balance > 0

# ✅ 推荐:每个条件独立检查
assert user.age > 18, "用户年龄不满足要求"
assert user.status == "active", "用户状态不是激活"
assert user.balance > 0, "用户余额不足"

三、断言失败处理:别让程序直接崩了

默认情况下,assert失败会抛出AssertionError,程序直接终止。但在测试框架里,我们通常希望「一个用例失败,不影响其他用例执行」。

怎么做?我一般用try-except包裹:

try:
    assert result == expected, f"期望{expected},实际{result}"
except AssertionError as e:
    print(f"断言失败: {e}")
    # 记录日志、截图、或者继续执行
    log_failure(e)

你想想看,如果每个断言失败都让程序崩溃,那跑100个测试用例,第一个就挂了,后面99个全白跑了。这显然不合理。

关键点:在自动化测试中,断言失败应该「记录错误,继续执行」,而不是「直接崩溃」。

另外,我建议给每个断言加上有意义的错误信息。别偷懒只写个assert a == b,失败了你连a和b的值都不知道。

# ❌ 不推荐
assert response.status_code == 200

# ✅ 推荐
assert response.status_code == 200, f"状态码异常,期望200,实际{response.status_code}"

四、Python内置断言:不止assert

很多人以为Python的断言只有assert语句。其实不然。Python标准库和测试框架里,藏着不少好用的断言工具。

1. unittest.TestCase的断言方法

如果你用unittest框架,它提供了一整套断言方法:

方法 用途
assertEqual(a, b) 检查a == b
assertTrue(x) 检查x为True
assertIn(a, b) 检查a in b
assertIsNone(x) 检查x is None
assertRaises(Exc) 检查是否抛出指定异常

我个人习惯用assertEqual和assertIn,因为它们比原生assert更语义化,失败信息也更清晰。

2. pytest的断言

pytest更绝——它直接重写了Python的assert,让你用原生assert就能获得详细的失败信息。

# pytest会自动解析断言表达式
def test_login():
    result = login("admin", "123456")
    assert result["code"] == 0
    assert result["msg"] == "登录成功"

pytest的断言失败时,会显示具体的变量值,比原生assert友好得多。

我的建议:如果你在写自动化测试,优先用pytest。它的断言机制更智能,能省去你写大量错误信息的功夫。

3. 第三方库的断言增强

还有一些库,比如assertpy、hamcrest,提供了更丰富的断言风格:

# assertpy 示例
from assertpy import assert_that

assert_that(result).is_equal_to(expected)
assert_that(response).has_status_code(200).has_header("Content-Type", "application/json")

这种链式调用的风格,读起来像自然语言,我个人挺喜欢的。不过要不要用,看团队习惯。

五、知识体系总览

说了这么多,咱们用一张图来梳理本章的核心内容:

断言基础知识体系 断言 (Assertion) assert 语句详解 语法: assert 条件, 信息 抛出 AssertionError 断言表达式设计 单一职责原则 有意义的错误信息 断言失败处理 try-except 捕获 记录日志继续执行 Python内置断言工具 unittest.TestCase 方法 pytest 智能断言 第三方库 (assertpy等)

六、总结一下

断言这东西,说简单也简单,说复杂也复杂。我见过不少测试工程师,写了几年自动化,断言还是只会用assert a == b。其实你想想看,断言的质量直接决定了测试用例的质量。

最后分享一个我自己的习惯:每次写完测试用例,我都会问自己三个问题:

  1. 这个断言真的能验证我的预期吗?
  2. 如果它失败了,我能一眼看出问题在哪吗?
  3. 它会不会因为环境波动而「假失败」?

这三个问题想清楚了,你的断言水平就上了一个台阶。

记住:好的断言,是测试用例的「眼睛」。它不仅要看得见,还要看得清、看得准。

好了,断言基础就聊到这儿。下一章咱们聊聊「断言策略」——什么时候该断言,什么时候不该断言,以及断言粒度怎么把握。这些可都是实战中经常踩的坑。


可可精品资料库