Coverage for tests / test_tutorial / test_fastapi / test_update / test_tutorial001.py: 100%

51 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-06-10 09:40 +0000

1import importlib 1ijklmnop

2from types import ModuleType 1ijklmnop

3 

4import pytest 1ijklmnop

5from dirty_equals import IsOneOf 1ijklmnop

6from fastapi.testclient import TestClient 1ijklmnop

7from sqlmodel import create_engine 1ijklmnop

8from sqlmodel.pool import StaticPool 1ijklmnop

9 

10 

11@pytest.fixture( 1ijklmnop

12 name="module", 

13 params=[ 

14 pytest.param("tutorial001_py310"), 

15 ], 

16) 

17def get_module(request: pytest.FixtureRequest) -> ModuleType: 1ijklmnop

18 mod = importlib.import_module(f"docs_src.tutorial.fastapi.update.{request.param}") 1ijklmnop

19 mod.sqlite_url = "sqlite://" 1ijklmnop

20 mod.engine = create_engine( 1ijklmnop

21 mod.sqlite_url, connect_args=mod.connect_args, poolclass=StaticPool 

22 ) 

23 return mod 1ijklmnop

24 

25 

26def test_tutorial(module: ModuleType): 1ijklmnop

27 with TestClient(module.app) as client: 1abcdefgh

28 hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} 1abcdefgh

29 hero2_data = { 1abcdefgh

30 "name": "Spider-Boy", 

31 "secret_name": "Pedro Parqueador", 

32 "id": 9000, 

33 } 

34 hero3_data = { 1abcdefgh

35 "name": "Rusty-Man", 

36 "secret_name": "Tommy Sharp", 

37 "age": 48, 

38 } 

39 response = client.post("/heroes/", json=hero1_data) 1abcdefgh

40 assert response.status_code == 200, response.text 1abcdefgh

41 response = client.post("/heroes/", json=hero2_data) 1abcdefgh

42 assert response.status_code == 200, response.text 1abcdefgh

43 hero2 = response.json() 1abcdefgh

44 hero2_id = hero2["id"] 1abcdefgh

45 response = client.post("/heroes/", json=hero3_data) 1abcdefgh

46 assert response.status_code == 200, response.text 1abcdefgh

47 hero3 = response.json() 1abcdefgh

48 hero3_id = hero3["id"] 1abcdefgh

49 response = client.get(f"/heroes/{hero2_id}") 1abcdefgh

50 assert response.status_code == 200, response.text 1abcdefgh

51 response = client.get("/heroes/9000") 1abcdefgh

52 assert response.status_code == 404, response.text 1abcdefgh

53 response = client.get("/heroes/") 1abcdefgh

54 assert response.status_code == 200, response.text 1abcdefgh

55 data = response.json() 1abcdefgh

56 assert len(data) == 3 1abcdefgh

57 

58 response = client.patch( 1abcdefgh

59 f"/heroes/{hero2_id}", json={"secret_name": "Spider-Youngster"} 

60 ) 

61 data = response.json() 1abcdefgh

62 assert response.status_code == 200, response.text 1abcdefgh

63 assert data["name"] == hero2_data["name"], "The name should not be set to none" 1abcdefgh

64 assert data["secret_name"] == "Spider-Youngster", ( 1abcdefgh

65 "The secret name should be updated" 

66 ) 

67 

68 response = client.patch(f"/heroes/{hero3_id}", json={"age": None}) 1abcdefgh

69 data = response.json() 1abcdefgh

70 assert response.status_code == 200, response.text 1abcdefgh

71 assert data["name"] == hero3_data["name"] 1abcdefgh

72 assert data["age"] is None, ( 1abcdefgh

73 "A field should be updatable to None, even if that's the default" 

74 ) 

75 

76 response = client.patch("/heroes/9001", json={"name": "Dragon Cube X"}) 1abcdefgh

77 assert response.status_code == 404, response.text 1abcdefgh

78 

79 response = client.get("/openapi.json") 1abcdefgh

80 assert response.status_code == 200, response.text 1abcdefgh

81 assert response.json() == { 1abcdefgh

82 "openapi": "3.1.0", 

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

84 "paths": { 

85 "/heroes/": { 

86 "get": { 

87 "summary": "Read Heroes", 

88 "operationId": "read_heroes_heroes__get", 

89 "parameters": [ 

90 { 

91 "required": False, 

92 "schema": { 

93 "title": "Offset", 

94 "type": "integer", 

95 "default": 0, 

96 }, 

97 "name": "offset", 

98 "in": "query", 

99 }, 

100 { 

101 "required": False, 

102 "schema": { 

103 "title": "Limit", 

104 "maximum": 100.0, 

105 "type": "integer", 

106 "default": 100, 

107 }, 

108 "name": "limit", 

109 "in": "query", 

110 }, 

111 ], 

112 "responses": { 

113 "200": { 

114 "description": "Successful Response", 

115 "content": { 

116 "application/json": { 

117 "schema": { 

118 "title": "Response Read Heroes Heroes Get", 

119 "type": "array", 

120 "items": { 

121 "$ref": "#/components/schemas/HeroPublic" 

122 }, 

123 } 

124 } 

125 }, 

126 }, 

127 "422": { 

128 "description": "Validation Error", 

129 "content": { 

130 "application/json": { 

131 "schema": { 

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

133 } 

134 } 

135 }, 

136 }, 

137 }, 

138 }, 

139 "post": { 

140 "summary": "Create Hero", 

141 "operationId": "create_hero_heroes__post", 

142 "requestBody": { 

143 "content": { 

144 "application/json": { 

145 "schema": { 

146 "$ref": "#/components/schemas/HeroCreate" 

147 } 

148 } 

149 }, 

150 "required": True, 

151 }, 

152 "responses": { 

153 "200": { 

154 "description": "Successful Response", 

155 "content": { 

156 "application/json": { 

157 "schema": { 

158 "$ref": "#/components/schemas/HeroPublic" 

159 } 

160 } 

161 }, 

162 }, 

163 "422": { 

164 "description": "Validation Error", 

165 "content": { 

166 "application/json": { 

167 "schema": { 

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

169 } 

170 } 

171 }, 

172 }, 

173 }, 

174 }, 

175 }, 

176 "/heroes/{hero_id}": { 

177 "get": { 

178 "summary": "Read Hero", 

179 "operationId": "read_hero_heroes__hero_id__get", 

180 "parameters": [ 

181 { 

182 "required": True, 

183 "schema": {"title": "Hero Id", "type": "integer"}, 

184 "name": "hero_id", 

185 "in": "path", 

186 } 

187 ], 

188 "responses": { 

189 "200": { 

190 "description": "Successful Response", 

191 "content": { 

192 "application/json": { 

193 "schema": { 

194 "$ref": "#/components/schemas/HeroPublic" 

195 } 

196 } 

197 }, 

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 }, 

211 "patch": { 

212 "summary": "Update Hero", 

213 "operationId": "update_hero_heroes__hero_id__patch", 

214 "parameters": [ 

215 { 

216 "required": True, 

217 "schema": {"title": "Hero Id", "type": "integer"}, 

218 "name": "hero_id", 

219 "in": "path", 

220 } 

221 ], 

222 "requestBody": { 

223 "content": { 

224 "application/json": { 

225 "schema": { 

226 "$ref": "#/components/schemas/HeroUpdate" 

227 } 

228 } 

229 }, 

230 "required": True, 

231 }, 

232 "responses": { 

233 "200": { 

234 "description": "Successful Response", 

235 "content": { 

236 "application/json": { 

237 "schema": { 

238 "$ref": "#/components/schemas/HeroPublic" 

239 } 

240 } 

241 }, 

242 }, 

243 "422": { 

244 "description": "Validation Error", 

245 "content": { 

246 "application/json": { 

247 "schema": { 

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

249 } 

250 } 

251 }, 

252 }, 

253 }, 

254 }, 

255 }, 

256 }, 

257 "components": { 

258 "schemas": { 

259 "HTTPValidationError": { 

260 "title": "HTTPValidationError", 

261 "type": "object", 

262 "properties": { 

263 "detail": { 

264 "title": "Detail", 

265 "type": "array", 

266 "items": { 

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

268 }, 

269 } 

270 }, 

271 }, 

272 "HeroCreate": { 

273 "title": "HeroCreate", 

274 "required": ["name", "secret_name"], 

275 "type": "object", 

276 "properties": { 

277 "name": {"title": "Name", "type": "string"}, 

278 "secret_name": {"title": "Secret Name", "type": "string"}, 

279 "age": { 

280 "title": "Age", 

281 "anyOf": [{"type": "integer"}, {"type": "null"}], 

282 }, 

283 }, 

284 }, 

285 "HeroPublic": { 

286 "title": "HeroPublic", 

287 "required": ["name", "secret_name", "id"], 

288 "type": "object", 

289 "properties": { 

290 "name": {"title": "Name", "type": "string"}, 

291 "secret_name": {"title": "Secret Name", "type": "string"}, 

292 "age": { 

293 "title": "Age", 

294 "anyOf": [{"type": "integer"}, {"type": "null"}], 

295 }, 

296 "id": {"title": "Id", "type": "integer"}, 

297 }, 

298 }, 

299 "HeroUpdate": { 

300 "title": "HeroUpdate", 

301 "type": "object", 

302 "properties": { 

303 "name": { 

304 "title": "Name", 

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

306 }, 

307 "secret_name": { 

308 "title": "Secret Name", 

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

310 }, 

311 "age": { 

312 "title": "Age", 

313 "anyOf": [{"type": "integer"}, {"type": "null"}], 

314 }, 

315 }, 

316 }, 

317 "ValidationError": { 

318 "title": "ValidationError", 

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

320 "type": "object", 

321 "properties": IsOneOf( 

322 { 

323 "loc": { 

324 "title": "Location", 

325 "type": "array", 

326 "items": { 

327 "anyOf": [ 

328 {"type": "string"}, 

329 {"type": "integer"}, 

330 ] 

331 }, 

332 }, 

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

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

335 }, 

336 { 

337 "loc": { 

338 "title": "Location", 

339 "type": "array", 

340 "items": { 

341 "anyOf": [ 

342 {"type": "string"}, 

343 {"type": "integer"}, 

344 ] 

345 }, 

346 }, 

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

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

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

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

351 }, 

352 ), 

353 }, 

354 } 

355 }, 

356 }