Coverage for tests / test_tutorial / test_body_nested_models / test_tutorial007.py: 100%
35 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
1import importlib 1abdc
3import pytest 1abdc
4from fastapi.testclient import TestClient 1abdc
5from inline_snapshot import snapshot 1abdc
7from ...utils import needs_py310 1abdc
10@pytest.fixture( 1abdc
11 name="client",
12 params=[
13 pytest.param("tutorial007_py310", marks=needs_py310),
14 ],
15)
16def get_client(request: pytest.FixtureRequest): 1abdc
17 mod = importlib.import_module(f"docs_src.body_nested_models.{request.param}") 1abc
19 client = TestClient(mod.app) 1abc
20 return client 1abc
23def test_post_all(client: TestClient): 1abdc
24 data = { 1efg
25 "name": "Special Offer",
26 "description": "This is a special offer",
27 "price": 38.6,
28 "items": [
29 {
30 "name": "Foo",
31 "description": "A very nice Item",
32 "price": 35.4,
33 "tax": 3.2,
34 "tags": ["foo"],
35 "images": [
36 {
37 "url": "http://example.com/image.png",
38 "name": "example image",
39 }
40 ],
41 }
42 ],
43 }
45 response = client.post( 1efg
46 "/offers/",
47 json=data,
48 )
49 assert response.status_code == 200, response.text 1efg
50 assert response.json() == data 1efg
53def test_put_only_required(client: TestClient): 1abdc
54 response = client.post( 1hij
55 "/offers/",
56 json={
57 "name": "Special Offer",
58 "price": 38.6,
59 "items": [
60 {
61 "name": "Foo",
62 "price": 35.4,
63 "images": [
64 {
65 "url": "http://example.com/image.png",
66 "name": "example image",
67 }
68 ],
69 }
70 ],
71 },
72 )
73 assert response.status_code == 200, response.text 1hij
74 assert response.json() == { 1hij
75 "name": "Special Offer",
76 "description": None,
77 "price": 38.6,
78 "items": [
79 {
80 "name": "Foo",
81 "description": None,
82 "price": 35.4,
83 "tax": None,
84 "tags": [],
85 "images": [
86 {
87 "url": "http://example.com/image.png",
88 "name": "example image",
89 }
90 ],
91 }
92 ],
93 }
96def test_put_empty_body(client: TestClient): 1abdc
97 response = client.post( 1klm
98 "/offers/",
99 json={},
100 )
101 assert response.status_code == 422, response.text 1klm
102 assert response.json() == { 1klm
103 "detail": [
104 {
105 "loc": ["body", "name"],
106 "input": {},
107 "msg": "Field required",
108 "type": "missing",
109 },
110 {
111 "loc": ["body", "price"],
112 "input": {},
113 "msg": "Field required",
114 "type": "missing",
115 },
116 {
117 "loc": ["body", "items"],
118 "input": {},
119 "msg": "Field required",
120 "type": "missing",
121 },
122 ]
123 }
126def test_put_missing_required_in_items(client: TestClient): 1abdc
127 response = client.post( 1nop
128 "/offers/",
129 json={
130 "name": "Special Offer",
131 "price": 38.6,
132 "items": [{}],
133 },
134 )
135 assert response.status_code == 422, response.text 1nop
136 assert response.json() == { 1nop
137 "detail": [
138 {
139 "loc": ["body", "items", 0, "name"],
140 "input": {},
141 "msg": "Field required",
142 "type": "missing",
143 },
144 {
145 "loc": ["body", "items", 0, "price"],
146 "input": {},
147 "msg": "Field required",
148 "type": "missing",
149 },
150 ]
151 }
154def test_put_missing_required_in_images(client: TestClient): 1abdc
155 response = client.post( 1qrs
156 "/offers/",
157 json={
158 "name": "Special Offer",
159 "price": 38.6,
160 "items": [
161 {"name": "Foo", "price": 35.4, "images": [{}]},
162 ],
163 },
164 )
165 assert response.status_code == 422, response.text 1qrs
166 assert response.json() == { 1qrs
167 "detail": [
168 {
169 "loc": ["body", "items", 0, "images", 0, "url"],
170 "input": {},
171 "msg": "Field required",
172 "type": "missing",
173 },
174 {
175 "loc": ["body", "items", 0, "images", 0, "name"],
176 "input": {},
177 "msg": "Field required",
178 "type": "missing",
179 },
180 ]
181 }
184def test_openapi_schema(client: TestClient): 1abdc
185 response = client.get("/openapi.json") 1tuv
186 assert response.status_code == 200, response.text 1tuv
187 assert response.json() == snapshot( 1tuv
188 {
189 "openapi": "3.1.0",
190 "info": {"title": "FastAPI", "version": "0.1.0"},
191 "paths": {
192 "/offers/": {
193 "post": {
194 "responses": {
195 "200": {
196 "description": "Successful Response",
197 "content": {"application/json": {"schema": {}}},
198 },
199 "422": {
200 "description": "Validation Error",
201 "content": {
202 "application/json": {
203 "schema": {
204 "$ref": "#/components/schemas/HTTPValidationError"
205 }
206 }
207 },
208 },
209 },
210 "summary": "Create Offer",
211 "operationId": "create_offer_offers__post",
212 "requestBody": {
213 "content": {
214 "application/json": {
215 "schema": {
216 "$ref": "#/components/schemas/Offer",
217 }
218 }
219 },
220 "required": True,
221 },
222 }
223 }
224 },
225 "components": {
226 "schemas": {
227 "Image": {
228 "properties": {
229 "url": {
230 "title": "Url",
231 "type": "string",
232 "format": "uri",
233 "maxLength": 2083,
234 "minLength": 1,
235 },
236 "name": {
237 "title": "Name",
238 "type": "string",
239 },
240 },
241 "required": ["url", "name"],
242 "title": "Image",
243 "type": "object",
244 },
245 "Item": {
246 "properties": {
247 "name": {
248 "title": "Name",
249 "type": "string",
250 },
251 "description": {
252 "title": "Description",
253 "anyOf": [{"type": "string"}, {"type": "null"}],
254 },
255 "price": {
256 "title": "Price",
257 "type": "number",
258 },
259 "tax": {
260 "title": "Tax",
261 "anyOf": [{"type": "number"}, {"type": "null"}],
262 },
263 "tags": {
264 "title": "Tags",
265 "default": [],
266 "type": "array",
267 "items": {"type": "string"},
268 "uniqueItems": True,
269 },
270 "images": {
271 "anyOf": [
272 {
273 "items": {
274 "$ref": "#/components/schemas/Image",
275 },
276 "type": "array",
277 },
278 {
279 "type": "null",
280 },
281 ],
282 "title": "Images",
283 },
284 },
285 "required": [
286 "name",
287 "price",
288 ],
289 "title": "Item",
290 "type": "object",
291 },
292 "Offer": {
293 "properties": {
294 "name": {
295 "title": "Name",
296 "type": "string",
297 },
298 "description": {
299 "title": "Description",
300 "anyOf": [{"type": "string"}, {"type": "null"}],
301 },
302 "price": {
303 "title": "Price",
304 "type": "number",
305 },
306 "items": {
307 "title": "Items",
308 "type": "array",
309 "items": {"$ref": "#/components/schemas/Item"},
310 },
311 },
312 "required": ["name", "price", "items"],
313 "title": "Offer",
314 "type": "object",
315 },
316 "ValidationError": {
317 "title": "ValidationError",
318 "required": ["loc", "msg", "type"],
319 "type": "object",
320 "properties": {
321 "loc": {
322 "title": "Location",
323 "type": "array",
324 "items": {
325 "anyOf": [{"type": "string"}, {"type": "integer"}]
326 },
327 },
328 "msg": {"title": "Message", "type": "string"},
329 "type": {"title": "Error Type", "type": "string"},
330 "input": {"title": "Input"},
331 "ctx": {"title": "Context", "type": "object"},
332 },
333 },
334 "HTTPValidationError": {
335 "title": "HTTPValidationError",
336 "type": "object",
337 "properties": {
338 "detail": {
339 "title": "Detail",
340 "type": "array",
341 "items": {
342 "$ref": "#/components/schemas/ValidationError"
343 },
344 }
345 },
346 },
347 }
348 },
349 }
350 )