如何使用pytest测试FastAPI的HTTPException异常场景
核心问题说明
你当前的代码有两个关键问题导致异常场景测不通:
/hello接口的try块内只有直接返回固定JSON的逻辑,不存在任何可能抛出requests.exceptions.HTTPError的操作,异常分支永远不会被执行- FastAPI内置的异常处理逻辑会自动把接口抛出的
HTTPException转换成对应状态码的HTTP响应返回给TestClient,异常不会直接抛到测试代码层,所以你写的pytest.raises(HTTPException)永远捕获不到。response.raise_for_status()是requests库自带的、根据响应状态码抛错的方法,和你接口内部抛出的异常没有关系。
测试实现方案
方案1:增加可控的异常触发参数(适合学习场景)
给接口加一个查询参数,手动控制是否触发异常分支,逻辑清晰最适合学习验证:
# main.py from fastapi import FastAPI, HTTPException import requests app = FastAPI() @app.get('/hello') def read_main(trigger_error: bool = False): try: if trigger_error: # 主动抛出requests的HTTPError,模拟真实场景下外部请求失败的情况 raise requests.exceptions.HTTPError("外部接口调用失败") return {"msg":"Hello World"} except requests.exceptions.HTTPError as e: raise HTTPException(status_code=400, detail='error occured')
对应的测试用例直接断言异常场景的响应即可,不需要捕获异常:
# test.py from fastapi.testclient import TestClient from main import app client = TestClient(app) def test_read_main(): response = client.get("/hello") assert response.status_code == 200 assert response.json() == {"msg":"Hello World"} def test_read_main_error(): # 传参触发异常分支 response = client.get("/hello", params={"trigger_error": True}) assert response.status_code == 400 assert response.json() == {"detail": "error occured"}
方案2:用Mock模拟异常(适合真实业务场景,不需要改业务代码)
如果你的业务接口本身在try块里有调用外部接口、数据库操作等可能抛错的逻辑,不需要额外加参数,直接用unittest.mock模拟对应逻辑抛出目标异常即可:
# test.py 补充Mock实现 from unittest import mock import requests from fastapi.testclient import TestClient from main import app client = TestClient(app) def test_read_main_error_with_mock(): # 假设try块内原本就有requests.get调用外部接口的逻辑,mock它抛错 with mock.patch("requests.get", side_effect=requests.exceptions.HTTPError("mock请求失败")): response = client.get("/hello") assert response.status_code == 400 assert response.json() == {"detail": "error occured"}
注意:mock的路径需要和你业务代码里实际调用抛错对象的路径保持一致,否则mock不会生效。
内容的提问来源于stack exchange,提问作者SpookyJelly
相关产品推荐
相关产品推荐

