Coverage for tests / test_validation_error_context.py: 100%
107 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
1from fastapi import FastAPI, Request, WebSocket 1abcd
2from fastapi.exceptions import ( 1abcd
3 RequestValidationError,
4 ResponseValidationError,
5 WebSocketRequestValidationError,
6)
7from fastapi.testclient import TestClient 1abcd
8from pydantic import BaseModel 1abcd
11class Item(BaseModel): 1abcd
12 id: int 1abcd
13 name: str 1abcd
16class ExceptionCapture: 1abcd
17 def __init__(self): 1abcd
18 self.exception = None 1abcd
20 def capture(self, exc): 1abcd
21 self.exception = exc 1keflmnghopqijrs
22 return exc 1keflmnghopqijrs
25app = FastAPI() 1abcd
26sub_app = FastAPI() 1abcd
27captured_exception = ExceptionCapture() 1abcd
29app.mount(path="/sub", app=sub_app) 1abcd
32@app.exception_handler(RequestValidationError) 1abcd
33@sub_app.exception_handler(RequestValidationError) 1abcd
34async def request_validation_handler(request: Request, exc: RequestValidationError): 1abcd
35 captured_exception.capture(exc) 1knq
36 raise exc 1knq
39@app.exception_handler(ResponseValidationError) 1abcd
40@sub_app.exception_handler(ResponseValidationError) 1abcd
41async def response_validation_handler(_: Request, exc: ResponseValidationError): 1abcd
42 captured_exception.capture(exc) 1efghij
43 raise exc 1efghij
46@app.exception_handler(WebSocketRequestValidationError) 1abcd
47@sub_app.exception_handler(WebSocketRequestValidationError) 1abcd
48async def websocket_validation_handler( 1abcd
49 websocket: WebSocket, exc: WebSocketRequestValidationError
50):
51 captured_exception.capture(exc) 1lmoprs
52 raise exc 1lmoprs
55@app.get("/users/{user_id}") 1abcd
56def get_user(user_id: int): 1abcd
57 return {"user_id": user_id} # pragma: no cover
60@app.get("/items/", response_model=Item) 1abcd
61def get_item(): 1abcd
62 return {"name": "Widget"} 1egi
65@sub_app.get("/items/", response_model=Item) 1abcd
66def get_sub_item(): 1abcd
67 return {"name": "Widget"} # pragma: no cover 1fhj
70@app.websocket("/ws/{item_id}") 1abcd
71async def websocket_endpoint(websocket: WebSocket, item_id: int): 1abcd
72 await websocket.accept() # pragma: no cover
73 await websocket.send_text(f"Item: {item_id}") # pragma: no cover
74 await websocket.close() # pragma: no cover
77@sub_app.websocket("/ws/{item_id}") 1abcd
78async def subapp_websocket_endpoint(websocket: WebSocket, item_id: int): 1abcd
79 await websocket.accept() # pragma: no cover
80 await websocket.send_text(f"Item: {item_id}") # pragma: no cover
81 await websocket.close() # pragma: no cover
84client = TestClient(app) 1abcd
87def test_request_validation_error_includes_endpoint_context(): 1abcd
88 captured_exception.exception = None 1knq
89 try: 1knq
90 client.get("/users/invalid") 1knq
91 except Exception: 1knq
92 pass 1knq
94 assert captured_exception.exception is not None 1knq
95 error_str = str(captured_exception.exception) 1knq
96 assert "get_user" in error_str 1knq
97 assert "/users/" in error_str 1knq
100def test_response_validation_error_includes_endpoint_context(): 1abcd
101 captured_exception.exception = None 1egi
102 try: 1egi
103 client.get("/items/") 1egi
104 except Exception: 1egi
105 pass 1egi
107 assert captured_exception.exception is not None 1egi
108 error_str = str(captured_exception.exception) 1egi
109 assert "get_item" in error_str 1egi
110 assert "/items/" in error_str 1egi
113def test_websocket_validation_error_includes_endpoint_context(): 1abcd
114 captured_exception.exception = None 1mps
115 try: 1mps
116 with client.websocket_connect("/ws/invalid"): 1mps
117 pass # pragma: no cover
118 except Exception: 1mps
119 pass 1mps
121 assert captured_exception.exception is not None 1mps
122 error_str = str(captured_exception.exception) 1mps
123 assert "websocket_endpoint" in error_str 1mps
124 assert "/ws/" in error_str 1mps
127def test_subapp_request_validation_error_includes_endpoint_context(): 1abcd
128 captured_exception.exception = None 1fhj
129 try: 1fhj
130 client.get("/sub/items/") 1fhj
131 except Exception: 1fhj
132 pass 1fhj
134 assert captured_exception.exception is not None 1fhj
135 error_str = str(captured_exception.exception) 1fhj
136 assert "get_sub_item" in error_str 1fhj
137 assert "/sub/items/" in error_str 1fhj
140def test_subapp_websocket_validation_error_includes_endpoint_context(): 1abcd
141 captured_exception.exception = None 1lor
142 try: 1lor
143 with client.websocket_connect("/sub/ws/invalid"): 1lor
144 pass # pragma: no cover
145 except Exception: 1lor
146 pass 1lor
148 assert captured_exception.exception is not None 1lor
149 error_str = str(captured_exception.exception) 1lor
150 assert "subapp_websocket_endpoint" in error_str 1lor
151 assert "/sub/ws/" in error_str 1lor
154def test_validation_error_with_only_path(): 1abcd
155 errors = [{"type": "missing", "loc": ("body", "name"), "msg": "Field required"}] 1wxy
156 exc = RequestValidationError(errors, endpoint_ctx={"path": "GET /api/test"}) 1wxy
157 error_str = str(exc) 1wxy
158 assert "Endpoint: GET /api/test" in error_str 1wxy
159 assert 'File "' not in error_str 1wxy
162def test_validation_error_with_no_context(): 1abcd
163 errors = [{"type": "missing", "loc": ("body", "name"), "msg": "Field required"}] 1tuv
164 exc = RequestValidationError(errors, endpoint_ctx={}) 1tuv
165 error_str = str(exc) 1tuv
166 assert "1 validation error:" in error_str 1tuv
167 assert "Endpoint" not in error_str 1tuv
168 assert 'File "' not in error_str 1tuv