pytest直接使用原生assert,无需继承TestCase或self.assert*方法;测试函数需以test_开头或_test结尾,assert失败时自动展开变量值并高亮原因。

pytest 里直接用 assert 就行,不用写 self.assertEqual
pytest 的核心设计就是让断言回归 Python 原生语义——你写什么,它就按什么报错。不需要继承 TestCase,不出现 self.assert* 系列方法。只要在测试函数里写 assert,pytest 就会自动捕获、重写、展开并高亮失败原因。
常见错误现象:有人照搬 unittest 写法,在 pytest 测试函数里写 self.assertEqual(a, b),结果报 AttributeError: 'TestSomething' object has no attribute 'assertEqual' ——因为没继承、也没 self 上下文。
- 测试函数必须是普通函数,以
test_开头或以_test结尾 - 不要加
class TestXXX(unittest.TestCase):这类结构(除非你明确想混用 unittest) -
assert后面跟任意合法 Python 表达式,比如assert len(items) == 3、assert "error" not in log_output
assert 失败时为什么能看清具体值?
因为 pytest 在运行时重写了 assert 语句的 AST,把原始表达式拆解成变量名 + 实际值 + 比较逻辑。不是靠异常消息拼接,而是编译期介入。
使用场景:当你写 assert response.status_code == 200 却失败了,pytest 不会只报 “AssertionError”,而是显示类似:
立即学习“Python免费学习笔记(深入)”;
assert 404 == 200 + where 404 = response.status_code
这依赖于 pytest 的 assertion rewriting 机制,默认开启;如果测试文件被动态导入或用 exec() 执行,可能失效。
- 确保测试文件后缀是
.py,且由 pytest 直接发现执行(如pytest test_api.py) - 禁用重写的配置项是
--assert=plain,一般别碰 - 自定义
__repr__或__str__会影响展示效果,但不影响断言逻辑
哪些 assert 写法容易踩坑?
不是所有 assert 表达式都能被清晰展开。pytest 对复杂链式调用、函数调用、布尔运算的支持有边界。
常见错误现象:写 assert get_user().name == "alice" 失败时只报 AssertionError,没有中间值提示;或者 assert a and b 失败后看不出哪个子表达式为假。
- 避免在
assert右侧直接调用函数,先赋值再断言:user = get_user(); assert user.name == "alice" -
assert x in y能展开,但assert not x in y展开效果弱,建议改写为assert x not in y - 多个条件用逗号拼一起(
assert a == 1, b == 2)是语法错误,正确是用and连接 - 浮点数比较慎用
==,优先用pytest.approx():assert result == pytest.approx(3.14, abs=1e-3)
需要更细粒度控制时,用 pytest.raises 和 pytest.warns
原生 assert 无法检查“是否抛出异常”或“是否发出警告”。这时候必须换专用上下文管理器。
使用场景:验证某段代码必须报 ValueError,或必须触发 DeprecationWarning。
- 写
assert raise ValueError是无效语法,会直接报错 - 正确写法是:
with pytest.raises(ValueError, match="invalid.*input"):+ 缩进执行代码 -
match参数支持正则,不填也能捕获,但推荐加上便于定位 - 警告检测同理:
with pytest.warns(DeprecationWarning):
这些上下文管理器本身不依赖 assertion rewriting,但它们内部仍会配合 pytest 的异常捕获机制做精准匹配。最容易被忽略的是:忘记缩进执行语句,导致上下文退出后才执行,断言永远不生效。










