pytest测试中异常场景下后续代码未终止执行的原因咨询
问题解析与原因说明
你这段测试代码里,当k=None时,t(k)明明抛出了ValueError,但看起来with块内t(k)之后的if/else代码好像还执行了,而且测试能通过——其实是你对pytest.raises的工作逻辑理解错了。
核心原因:pytest.raises的执行机制
pytest.raises是专门用来捕获并验证异常的上下文管理器,它的流程和普通try/except不一样:
- 进入
with块时,它会准备好捕获指定类型的异常 - 当块内代码抛出符合要求的异常时,它会把异常对象存到
ex.value里,然后告诉Python“这个异常已经处理完了” - 但异常发生点之后的代码根本不会执行
你觉得后续代码执行了,其实是误解——当k=None时,kk = t(k)这一行抛出异常后,后面的if/else断言完全没跑,测试能通过只是因为pytest.raises成功捕获到了预期的异常,和你写的else分支断言没关系。
修正你的测试代码
你的测试逻辑有问题,应该把断言放到with块外面,分场景验证:
from contextlib import nullcontext as does_not_raise import pytest def t(k): if k: return k else: raise ValueError("Value") @pytest.mark.parametrize("k, cntxt", [(None, pytest.raises(ValueError)), ("Value", does_not_raise())]) def test_t(k, cntxt): with cntxt as ex: kk = t(k) # 把断言移到with块外,确保两种场景都能正确验证 if k: assert kk == k assert ex is None else: assert str(ex.value) == "Value"
这样改了之后:
- 当
k="Value"时,with块正常执行完,kk拿到返回值,后续断言验证结果 - 当
k=None时,with块捕获到异常,ex.value保存了异常信息,后续断言验证异常内容
额外说明:does_not_raise的作用
这个空上下文管理器就是为了让两种测试场景的代码结构统一,不需要写两套逻辑,符合参数化测试的简洁性要求。
内容的提问来源于stack exchange,提问作者Draqun
相关产品推荐
相关产品推荐

