Coverage for tests / test_annotated.py: 100%
60 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 typing import Annotated 1abcd
3import pytest 1abcd
4from fastapi import APIRouter, FastAPI, Query 1abcd
5from fastapi.testclient import TestClient 1abcd
6from inline_snapshot import snapshot 1abcd
8app = FastAPI() 1abcd
11@app.get("/default") 1abcd
12async def default(foo: Annotated[str, Query()] = "foo"): 1abcd
13 return {"foo": foo} 1klm
16@app.get("/required") 1abcd
17async def required(foo: Annotated[str, Query(min_length=1)]): 1abcd
18 return {"foo": foo} 1klm
21@app.get("/multiple") 1abcd
22async def multiple(foo: Annotated[str, object(), Query(min_length=1)]): 1abcd
23 return {"foo": foo} 1klm
26@app.get("/unrelated") 1abcd
27async def unrelated(foo: Annotated[str, object()]): 1abcd
28 return {"foo": foo} 1klm
31client = TestClient(app) 1abcd
33foo_is_missing = { 1abcd
34 "detail": [
35 {
36 "loc": ["query", "foo"],
37 "msg": "Field required",
38 "type": "missing",
39 "input": None,
40 }
41 ]
42}
43foo_is_short = { 1abcd
44 "detail": [
45 {
46 "ctx": {"min_length": 1},
47 "loc": ["query", "foo"],
48 "msg": "String should have at least 1 character",
49 "type": "string_too_short",
50 "input": "",
51 }
52 ]
53}
56@pytest.mark.parametrize( 1abcd
57 "path,expected_status,expected_response",
58 [
59 ("/default", 200, {"foo": "foo"}),
60 ("/default?foo=bar", 200, {"foo": "bar"}),
61 ("/required?foo=bar", 200, {"foo": "bar"}),
62 ("/required", 422, foo_is_missing),
63 ("/required?foo=", 422, foo_is_short),
64 ("/multiple?foo=bar", 200, {"foo": "bar"}),
65 ("/multiple", 422, foo_is_missing),
66 ("/multiple?foo=", 422, foo_is_short),
67 ("/unrelated?foo=bar", 200, {"foo": "bar"}),
68 ("/unrelated", 422, foo_is_missing),
69 ],
70)
71def test_get(path, expected_status, expected_response): 1abcd
72 response = client.get(path) 1klm
73 assert response.status_code == expected_status 1klm
74 assert response.json() == expected_response 1klm
77def test_multiple_path(): 1abcd
78 app = FastAPI() 1efg
80 @app.get("/test1") 1efg
81 @app.get("/test2") 1efg
82 async def test(var: Annotated[str, Query()] = "bar"): 1efg
83 return {"foo": var} 1efg
85 client = TestClient(app) 1efg
86 response = client.get("/test1") 1efg
87 assert response.status_code == 200 1efg
88 assert response.json() == {"foo": "bar"} 1efg
90 response = client.get("/test1", params={"var": "baz"}) 1efg
91 assert response.status_code == 200 1efg
92 assert response.json() == {"foo": "baz"} 1efg
94 response = client.get("/test2") 1efg
95 assert response.status_code == 200 1efg
96 assert response.json() == {"foo": "bar"} 1efg
98 response = client.get("/test2", params={"var": "baz"}) 1efg
99 assert response.status_code == 200 1efg
100 assert response.json() == {"foo": "baz"} 1efg
103def test_nested_router(): 1abcd
104 app = FastAPI() 1hij
106 router = APIRouter(prefix="/nested") 1hij
108 @router.get("/test") 1hij
109 async def test(var: Annotated[str, Query()] = "bar"): 1hij
110 return {"foo": var} 1hij
112 app.include_router(router) 1hij
114 client = TestClient(app) 1hij
116 response = client.get("/nested/test") 1hij
117 assert response.status_code == 200 1hij
118 assert response.json() == {"foo": "bar"} 1hij
121def test_openapi_schema(): 1abcd
122 response = client.get("/openapi.json") 1nop
123 assert response.status_code == 200 1nop
124 assert response.json() == snapshot( 1nop
125 {
126 "openapi": "3.1.0",
127 "info": {"title": "FastAPI", "version": "0.1.0"},
128 "paths": {
129 "/default": {
130 "get": {
131 "summary": "Default",
132 "operationId": "default_default_get",
133 "parameters": [
134 {
135 "required": False,
136 "schema": {
137 "title": "Foo",
138 "type": "string",
139 "default": "foo",
140 },
141 "name": "foo",
142 "in": "query",
143 }
144 ],
145 "responses": {
146 "200": {
147 "description": "Successful Response",
148 "content": {"application/json": {"schema": {}}},
149 },
150 "422": {
151 "description": "Validation Error",
152 "content": {
153 "application/json": {
154 "schema": {
155 "$ref": "#/components/schemas/HTTPValidationError"
156 }
157 }
158 },
159 },
160 },
161 }
162 },
163 "/required": {
164 "get": {
165 "summary": "Required",
166 "operationId": "required_required_get",
167 "parameters": [
168 {
169 "required": True,
170 "schema": {
171 "title": "Foo",
172 "minLength": 1,
173 "type": "string",
174 },
175 "name": "foo",
176 "in": "query",
177 }
178 ],
179 "responses": {
180 "200": {
181 "description": "Successful Response",
182 "content": {"application/json": {"schema": {}}},
183 },
184 "422": {
185 "description": "Validation Error",
186 "content": {
187 "application/json": {
188 "schema": {
189 "$ref": "#/components/schemas/HTTPValidationError"
190 }
191 }
192 },
193 },
194 },
195 }
196 },
197 "/multiple": {
198 "get": {
199 "summary": "Multiple",
200 "operationId": "multiple_multiple_get",
201 "parameters": [
202 {
203 "required": True,
204 "schema": {
205 "title": "Foo",
206 "minLength": 1,
207 "type": "string",
208 },
209 "name": "foo",
210 "in": "query",
211 }
212 ],
213 "responses": {
214 "200": {
215 "description": "Successful Response",
216 "content": {"application/json": {"schema": {}}},
217 },
218 "422": {
219 "description": "Validation Error",
220 "content": {
221 "application/json": {
222 "schema": {
223 "$ref": "#/components/schemas/HTTPValidationError"
224 }
225 }
226 },
227 },
228 },
229 }
230 },
231 "/unrelated": {
232 "get": {
233 "summary": "Unrelated",
234 "operationId": "unrelated_unrelated_get",
235 "parameters": [
236 {
237 "required": True,
238 "schema": {"title": "Foo", "type": "string"},
239 "name": "foo",
240 "in": "query",
241 }
242 ],
243 "responses": {
244 "200": {
245 "description": "Successful Response",
246 "content": {"application/json": {"schema": {}}},
247 },
248 "422": {
249 "description": "Validation Error",
250 "content": {
251 "application/json": {
252 "schema": {
253 "$ref": "#/components/schemas/HTTPValidationError"
254 }
255 }
256 },
257 },
258 },
259 }
260 },
261 },
262 "components": {
263 "schemas": {
264 "HTTPValidationError": {
265 "title": "HTTPValidationError",
266 "type": "object",
267 "properties": {
268 "detail": {
269 "title": "Detail",
270 "type": "array",
271 "items": {
272 "$ref": "#/components/schemas/ValidationError"
273 },
274 }
275 },
276 },
277 "ValidationError": {
278 "title": "ValidationError",
279 "required": ["loc", "msg", "type"],
280 "type": "object",
281 "properties": {
282 "loc": {
283 "title": "Location",
284 "type": "array",
285 "items": {
286 "anyOf": [{"type": "string"}, {"type": "integer"}]
287 },
288 },
289 "msg": {"title": "Message", "type": "string"},
290 "type": {"title": "Error Type", "type": "string"},
291 "input": {"title": "Input"},
292 "ctx": {"title": "Context", "type": "object"},
293 },
294 },
295 }
296 },
297 }
298 )