Coverage for tests / test_tutorial / test_body_nested_models / test_tutorial004.py: 100%

35 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-12 18:15 +0000

1import importlib 1abdc

2 

3import pytest 1abdc

4from dirty_equals import IsList 1abdc

5from fastapi.testclient import TestClient 1abdc

6from inline_snapshot import snapshot 1abdc

7 

8from ...utils import needs_py310 1abdc

9 

10 

11@pytest.fixture( 1abdc

12 name="client", 

13 params=[ 

14 pytest.param("tutorial004_py310", marks=needs_py310), 

15 ], 

16) 

17def get_client(request: pytest.FixtureRequest): 1abdc

18 mod = importlib.import_module(f"docs_src.body_nested_models.{request.param}") 1abc

19 

20 client = TestClient(mod.app) 1abc

21 return client 1abc

22 

23 

24def test_put_all(client: TestClient): 1abdc

25 response = client.put( 1efg

26 "/items/123", 

27 json={ 

28 "name": "Foo", 

29 "description": "A very nice Item", 

30 "price": 35.4, 

31 "tax": 3.2, 

32 "tags": ["foo", "bar", "foo"], 

33 "image": {"url": "http://example.com/image.png", "name": "example image"}, 

34 }, 

35 ) 

36 assert response.status_code == 200, response.text 1efg

37 assert response.json() == { 1efg

38 "item_id": 123, 

39 "item": { 

40 "name": "Foo", 

41 "description": "A very nice Item", 

42 "price": 35.4, 

43 "tax": 3.2, 

44 "tags": IsList("foo", "bar", check_order=False), 

45 "image": {"url": "http://example.com/image.png", "name": "example image"}, 

46 }, 

47 } 

48 

49 

50def test_put_only_required(client: TestClient): 1abdc

51 response = client.put( 1hij

52 "/items/5", 

53 json={"name": "Foo", "price": 35.4}, 

54 ) 

55 assert response.status_code == 200, response.text 1hij

56 assert response.json() == { 1hij

57 "item_id": 5, 

58 "item": { 

59 "name": "Foo", 

60 "description": None, 

61 "price": 35.4, 

62 "tax": None, 

63 "tags": [], 

64 "image": None, 

65 }, 

66 } 

67 

68 

69def test_put_empty_body(client: TestClient): 1abdc

70 response = client.put( 1klm

71 "/items/5", 

72 json={}, 

73 ) 

74 assert response.status_code == 422, response.text 1klm

75 assert response.json() == { 1klm

76 "detail": [ 

77 { 

78 "loc": ["body", "name"], 

79 "input": {}, 

80 "msg": "Field required", 

81 "type": "missing", 

82 }, 

83 { 

84 "loc": ["body", "price"], 

85 "input": {}, 

86 "msg": "Field required", 

87 "type": "missing", 

88 }, 

89 ] 

90 } 

91 

92 

93def test_put_missing_required_in_item(client: TestClient): 1abdc

94 response = client.put( 1nop

95 "/items/5", 

96 json={"description": "A very nice Item"}, 

97 ) 

98 assert response.status_code == 422, response.text 1nop

99 assert response.json() == { 1nop

100 "detail": [ 

101 { 

102 "loc": ["body", "name"], 

103 "input": {"description": "A very nice Item"}, 

104 "msg": "Field required", 

105 "type": "missing", 

106 }, 

107 { 

108 "loc": ["body", "price"], 

109 "input": {"description": "A very nice Item"}, 

110 "msg": "Field required", 

111 "type": "missing", 

112 }, 

113 ] 

114 } 

115 

116 

117def test_put_missing_required_in_image(client: TestClient): 1abdc

118 response = client.put( 1qrs

119 "/items/5", 

120 json={ 

121 "name": "Foo", 

122 "price": 35.4, 

123 "image": {"url": "http://example.com/image.png"}, 

124 }, 

125 ) 

126 assert response.status_code == 422, response.text 1qrs

127 assert response.json() == { 1qrs

128 "detail": [ 

129 { 

130 "loc": ["body", "image", "name"], 

131 "input": {"url": "http://example.com/image.png"}, 

132 "msg": "Field required", 

133 "type": "missing", 

134 }, 

135 ] 

136 } 

137 

138 

139def test_openapi_schema(client: TestClient): 1abdc

140 response = client.get("/openapi.json") 1tuv

141 assert response.status_code == 200, response.text 1tuv

142 assert response.json() == snapshot( 1tuv

143 { 

144 "openapi": "3.1.0", 

145 "info": {"title": "FastAPI", "version": "0.1.0"}, 

146 "paths": { 

147 "/items/{item_id}": { 

148 "put": { 

149 "parameters": [ 

150 { 

151 "in": "path", 

152 "name": "item_id", 

153 "required": True, 

154 "schema": { 

155 "title": "Item Id", 

156 "type": "integer", 

157 }, 

158 }, 

159 ], 

160 "responses": { 

161 "200": { 

162 "description": "Successful Response", 

163 "content": {"application/json": {"schema": {}}}, 

164 }, 

165 "422": { 

166 "description": "Validation Error", 

167 "content": { 

168 "application/json": { 

169 "schema": { 

170 "$ref": "#/components/schemas/HTTPValidationError" 

171 } 

172 } 

173 }, 

174 }, 

175 }, 

176 "summary": "Update Item", 

177 "operationId": "update_item_items__item_id__put", 

178 "requestBody": { 

179 "content": { 

180 "application/json": { 

181 "schema": { 

182 "$ref": "#/components/schemas/Item", 

183 } 

184 } 

185 }, 

186 "required": True, 

187 }, 

188 } 

189 } 

190 }, 

191 "components": { 

192 "schemas": { 

193 "Image": { 

194 "properties": { 

195 "url": { 

196 "title": "Url", 

197 "type": "string", 

198 }, 

199 "name": { 

200 "title": "Name", 

201 "type": "string", 

202 }, 

203 }, 

204 "required": ["url", "name"], 

205 "title": "Image", 

206 "type": "object", 

207 }, 

208 "Item": { 

209 "properties": { 

210 "name": { 

211 "title": "Name", 

212 "type": "string", 

213 }, 

214 "description": { 

215 "title": "Description", 

216 "anyOf": [{"type": "string"}, {"type": "null"}], 

217 }, 

218 "price": { 

219 "title": "Price", 

220 "type": "number", 

221 }, 

222 "tax": { 

223 "title": "Tax", 

224 "anyOf": [{"type": "number"}, {"type": "null"}], 

225 }, 

226 "tags": { 

227 "title": "Tags", 

228 "default": [], 

229 "type": "array", 

230 "items": {"type": "string"}, 

231 "uniqueItems": True, 

232 }, 

233 "image": { 

234 "anyOf": [ 

235 {"$ref": "#/components/schemas/Image"}, 

236 {"type": "null"}, 

237 ], 

238 }, 

239 }, 

240 "required": [ 

241 "name", 

242 "price", 

243 ], 

244 "title": "Item", 

245 "type": "object", 

246 }, 

247 "ValidationError": { 

248 "title": "ValidationError", 

249 "required": ["loc", "msg", "type"], 

250 "type": "object", 

251 "properties": { 

252 "loc": { 

253 "title": "Location", 

254 "type": "array", 

255 "items": { 

256 "anyOf": [{"type": "string"}, {"type": "integer"}] 

257 }, 

258 }, 

259 "msg": {"title": "Message", "type": "string"}, 

260 "type": {"title": "Error Type", "type": "string"}, 

261 "input": {"title": "Input"}, 

262 "ctx": {"title": "Context", "type": "object"}, 

263 }, 

264 }, 

265 "HTTPValidationError": { 

266 "title": "HTTPValidationError", 

267 "type": "object", 

268 "properties": { 

269 "detail": { 

270 "title": "Detail", 

271 "type": "array", 

272 "items": { 

273 "$ref": "#/components/schemas/ValidationError" 

274 }, 

275 } 

276 }, 

277 }, 

278 } 

279 }, 

280 } 

281 )