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