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

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

9 

10 

11class Item(BaseModel): 1adbc

12 id: int 1abc

13 name: str 1abc

14 

15 

16class ExceptionCapture: 1adbc

17 def __init__(self): 1adbc

18 self.exception = None 1adbc

19 

20 def capture(self, exc): 1adbc

21 self.exception = exc 1lefmnogphiqrsjktu

22 return exc 1lefmnogphiqrsjktu

23 

24 

25app = FastAPI() 1adbc

26sub_app = FastAPI() 1adbc

27captured_exception = ExceptionCapture() 1adbc

28 

29app.mount(path="/sub", app=sub_app) 1adbc

30 

31 

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

37 

38 

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

44 

45 

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

53 

54 

55@app.get("/users/{user_id}") 1adbc

56def get_user(user_id: int): 1adbc

57 return {"user_id": user_id} # pragma: no cover 

58 

59 

60@app.get("/items/", response_model=Item) 1adbc

61def get_item(): 1adbc

62 return {"name": "Widget"} 1eghj

63 

64 

65@sub_app.get("/items/", response_model=Item) 1adbc

66def get_sub_item(): 1adbc

67 return {"name": "Widget"} # pragma: no cover 1fvik

68 

69 

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 

75 

76 

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 

82 

83 

84client = TestClient(app) 1adbc

85 

86 

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

93 

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

98 

99 

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

106 

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

111 

112 

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

120 

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

125 

126 

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

133 

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

138 

139 

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

147 

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

152 

153 

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

160 

161 

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