5:原生 assert 断言
上篇讲解 Pytest 类 & 方法级前后置 setup_class/setup_method,本篇聚焦测试核心:断言。自动化用例靠断言判定执行结果,Pytest 摒弃 unittest 繁琐断言方法,直接使用 Python 原生 assert,简洁高效,是接口、UI 自动化高频用法。
一、什么是断言?Pytest 选用原生 assert 的优势
断言用来校验程序实际结果与预期结果是否一致:条件为 True,用例通过;条件为 False,抛出 AssertionError,用例失败终止执行。
对比 unittest,Pytest assert 两大优点
- 语法极简:不用记忆self.assertEqual、self.assertIn、self.assertTrue等一堆方法,直接用原生运算符==、>、in、is,降低学习成本。
- 报错详情自动解析:Pytest 底层重写 assert,失败自动打印实际值、期望值、变量来源、数据差异,不用手动拼接日志排查问题。
unittest 冗余示例:
import unittest class TestDemo(unittest.TestCase): def test_01(self): res = 2+3 self.assertEqual(res,6,"结果错误")Pytest 简洁写法:
def test_01(): res = 2+3 assert res ==6, f"预期6,实际{res}"二、assert 基础语法
assert 布尔表达式, "自定义失败提示文案(可选)"- 布尔表达式:满足条件 = True → 用例放行;不满足 = False → 断言失败
- 自定义提示:失败时优先展示自定义信息,便于快速定位业务问题,自动化项目必加
基础示例:
# test_assert_base.py def test_assert_demo(): expect = 200 actual = 200 # 成功,无报错 assert actual == expect # 失败,抛出异常+自定义提示 actual2 = 500 assert actual2 == expect, f"接口状态码异常:预期{expect},实际{actual2}"执行:pytest -vs test_assert_base.py
三、自动化高频场景:全类型断言实战(接口测试最常用)
1. 数值断言(状态码、数字结果)
==、!=、>、>=、<、<=,多用于接口响应码、返回数值校验
def test_num_assert(): code = 200 # 等于 assert code == 200, "请求成功状态码必须200" # 大于 assert code > 100 # 不等于 assert code != 5002. 字符串断言(返回文本、错误信息)
in / not in、==,校验返回内容是否包含指定关键字
def test_str_assert(): res_text = "login success" assert "success" in res_text, "登录返回结果不含success" assert "fail" not in res_text3. 列表 / 元组断言(批量返回数据)
长度、成员存在性校验
def test_list_assert(): data_list = [10,20,30] # 判断长度 assert len(data_list) ==3, "返回数据条数错误" # 判断元素存在 assert 20 in data_list4. 字典断言(接口返回 JSON,接口自动化重中之重)
键存在、键值匹配,90% 接口用例都会用到
def test_dict_assert(): resp = {"code":200,"msg":"ok","data":{"uid":1001}} # 校验key是否存在 assert "code" in resp # 校验value assert resp["code"] ==200 # 嵌套字典取值断言 assert resp["data"]["uid"] ==10015. 布尔值断言
def test_bool_assert(): flag = True assert flag is True四、pytest.raises 异常断言:预判代码抛出指定异常
部分用例需要校验错误入参是否抛出预期异常,不用 try-except 捕获
使用with pytest.raises(异常类型)实现,异常匹配则用例通过,未抛异常则失败。
基础用法
import pytest def test_exception(): # 预期传入非数字字符串,触发ValueError with pytest.raises(ValueError): int("abc123")进阶:捕获异常信息
def test_exception_msg(): with pytest.raises(ValueError) as err_info: int("test") # 断言异常描述包含指定内容 assert "invalid literal for int()" in str(err_info.value)五、自定义报错信息规范(项目实战最佳实践)
不要只写assert xxx ==xx,"断言失败"模糊提示,规范格式:assert 条件, f"【业务场景】预期XX,实际XX"
# 规范写法 resp_code = 404 expect_code =200 assert resp_code == expect_code, f"【用户登录接口】状态码异常:预期{expect_code},实际{resp_code}"好处:流水线报错一眼定位接口与问题,节省排查时间。
六、Pytest 自动优化:复杂数据断言差异化报错
原生 Pytest 对长字符串、字典、列表会自动对比差异:
- 字符串不一致:高亮不同字符位置
- 字典不一致:标出 key 和 value 差异
- 列表不一致:提示第一个不匹配下标 示例报错:
E assert {'code': 200, 'msg': 'ok'} == {'code': 500, 'msg': 'fail'} E Differing items: E {'code': 200 != 500, 'msg': 'ok' != 'fail'}七、开发踩坑注意事项
- 不要在 assert 表达式中写业务逻辑:Python 使用
python -O运行时会全局禁用所有 assert,表达式内代码不会执行,只做结果判断。
# 错误:删除数据写在断言里,-O执行时代码失效 assert del_data() == True # 正确:逻辑前置,只断言结果 res = del_data() assert res == True- 自定义提示要用 f-string 动态拼接实际值,固定文案无排查意义。
八、前后置 + 断言综合实战(整合上篇知识点)
类前置统一初始化请求、方法前置单用例准备数据,最后用断言校验结果,企业标准用例模板
class TestLoginApi: def setup_class(self): print("【类前置】初始化请求头、全局url") self.headers = {"Content-Type":"application/json"} def setup_method(self): print("【方法前置】准备账号数据") self.account = {"user":"test01","pwd":"123456"} def test_login_success(self): # 模拟接口返回 resp = {"code":200,"msg":"登录成功"} # 多层断言 assert resp["code"] ==200, f"登录失败,状态码{resp['code']}" assert "成功" in resp["msg"]