pytest.raises未捕获异常主因是被测代码未在with块内执行或异常被try/except吞掉;需用as捕获实例做消息断言;异步函数须await调用并配asyncio插件;不支持unittest式参数传入,必须块内显式调用。

pytest.raises 为什么没捕获到异常?
常见现象是写了 with pytest.raises(ValueError),但测试直接失败,报错说“未抛出预期异常”。根本原因往往是:被测代码没在 with 块里执行,或者异常被提前吞掉了。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 确保所有可能抛出异常的代码(包括函数调用、表达式求值)都严格写在
with pytest.raises(...)的缩进块内 - 别在
with块外调用函数再传参,比如result = func(x); assert result == ...—— 这样异常在进入with前就炸了 - 检查是否用了
try/except包裹了被测逻辑,尤其是测试函数内部或被测函数里有静默吞异常的逻辑 - 如果被测函数返回一个可调用对象(比如闭包),记得要加括号调用:
with pytest.raises(...): factory()(),否则只是获取函数对象,不触发异常
怎么拿到抛出的异常实例做进一步断言?
只确认“抛了 ValueError”往往不够,比如还要验证错误信息是否含特定关键词,或检查异常的某个属性。这时不能只写 pytest.raises,得把它赋值给一个变量。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
as捕获异常实例:with pytest.raises(ValueError) as exc_info: - 之后通过
exc_info.value访问异常对象,比如assert "missing" in str(exc_info.value) - 注意
exc_info.type是异常类(ValueError),exc_info.value是实例,别混淆 - 不要对
exc_info本身做字符串转换,它不是异常对象,是ExceptionInfo类型的容器
pytest.raises 能否用于异步函数?
不能直接用。pytest.raises 是同步上下文管理器,而 async def 函数返回的是协程对象,不是立即执行的代码。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 必须用
await触发执行,所以得写成:with pytest.raises(ValueError): await async_func() - 测试函数本身也得是
async def,且 pytest 需启用 asyncio 插件(如pytest-asyncio),否则会报RuntimeWarning: coroutine 'xxx' was never awaited - 别漏掉
pytest.mark.asyncio装饰器(如果用pytest-asyncio),否则测试不会以协程方式运行 - 如果不用插件,只能手动创建事件循环并
run_until_complete,但更易出错,不推荐
为什么 assertRaises 和 pytest.raises 行为不一致?
Python 标准库的 self.assertRaises(unittest)和 pytest.raises 最大区别在于:前者接受函数和参数分开传入(惰性调用),后者要求代码块内执行(即时执行)。这导致参数传递方式完全不同。
实操建议:
立即学习“Python免费学习笔记(深入)”;
-
self.assertRaises(ValueError, func, arg1, arg2)是合法的;但pytest.raises(ValueError, func, arg1, arg2)会报错 ——pytest.raises不支持这种调用形式 - 必须显式写调用:
with pytest.raises(ValueError): func(arg1, arg2) - 如果参数复杂(比如带 lambda 或嵌套调用),容易因作用域或求值时机出错,建议先赋值再调用:
args = (x, y); with pytest.raises(...): func(*args) - 注意默认情况下
pytest.raises不检查异常类型继承关系(比如ValueError不匹配MyCustomError(ValueError)),除非显式设match=...或用isinstance手动判断
最常被忽略的是:异常消息的空格、换行、引号格式,哪怕多一个空格都会让 match= 断言失败;还有就是异步测试忘了配插件或装饰器,报错信息又不直指问题,容易卡很久。


















