Coverage for tests / test_tutorial / test_fastapi / test_multiple_models / test_tutorial002.py: 100%

52 statements  

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

1import importlib 1jklmnopqr

2from types import ModuleType 1jklmnopqr

3 

4import pytest 1jklmnopqr

5from fastapi.testclient import TestClient 1jklmnopqr

6from sqlalchemy import inspect 1jklmnopqr

7from sqlalchemy.engine.reflection import Inspector 1jklmnopqr

8from sqlmodel import create_engine 1jklmnopqr

9from sqlmodel.pool import StaticPool 1jklmnopqr

10 

11from tests.conftest import needs_py310 1jklmnopqr

12 

13 

14@pytest.fixture( 1jklmnopqr

15 name="module", 

16 params=[ 

17 pytest.param("tutorial002_py39"), 

18 pytest.param("tutorial002_py310", marks=needs_py310), 

19 ], 

20) 

21def get_module(request: pytest.FixtureRequest) -> ModuleType: 1jklmnopqr

22 mod = importlib.import_module( 1jklmnopqr

23 f"docs_src.tutorial.fastapi.multiple_models.{request.param}" 

24 ) 

25 mod.sqlite_url = "sqlite://" 1jklmnopqr

26 mod.engine = create_engine( 1jklmnopqr

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

28 ) 

29 return mod 1jklmnopqr

30 

31 

32def test_tutorial(module: ModuleType): 1jklmnopqr

33 with TestClient(module.app) as client: 1abcdefghi

34 hero1_data = {"name": "Deadpond", "secret_name": "Dive Wilson"} 1abcdefghi

35 hero2_data = { 1abcdefghi

36 "name": "Spider-Boy", 

37 "secret_name": "Pedro Parqueador", 

38 "id": 9000, 

39 } 

40 response = client.post("/heroes/", json=hero1_data) 1abcdefghi

41 data = response.json() 1abcdefghi

42 

43 assert response.status_code == 200, response.text 1abcdefghi

44 assert data["name"] == hero1_data["name"] 1abcdefghi

45 assert data["secret_name"] == hero1_data["secret_name"] 1abcdefghi

46 assert data["id"] is not None 1abcdefghi

47 assert data["age"] is None 1abcdefghi

48 

49 response = client.post("/heroes/", json=hero2_data) 1abcdefghi

50 data = response.json() 1abcdefghi

51 

52 assert response.status_code == 200, response.text 1abcdefghi

53 assert data["name"] == hero2_data["name"] 1abcdefghi

54 assert data["secret_name"] == hero2_data["secret_name"] 1abcdefghi

55 assert data["id"] != hero2_data["id"], ( 1abcdefghi

56 "Now it's not possible to predefine the ID from the request, " 

57 "it's now set by the database" 

58 ) 

59 assert data["age"] is None 1abcdefghi

60 

61 response = client.get("/heroes/") 1abcdefghi

62 data = response.json() 1abcdefghi

63 

64 assert response.status_code == 200, response.text 1abcdefghi

65 assert len(data) == 2 1abcdefghi

66 assert data[0]["name"] == hero1_data["name"] 1abcdefghi

67 assert data[0]["secret_name"] == hero1_data["secret_name"] 1abcdefghi

68 assert data[1]["name"] == hero2_data["name"] 1abcdefghi

69 assert data[1]["secret_name"] == hero2_data["secret_name"] 1abcdefghi

70 assert data[1]["id"] != hero2_data["id"] 1abcdefghi

71 

72 response = client.get("/openapi.json") 1abcdefghi

73 

74 assert response.status_code == 200, response.text 1abcdefghi

75 

76 assert response.json() == { 1abcdefghi

77 "openapi": "3.1.0", 

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

79 "paths": { 

80 "/heroes/": { 

81 "get": { 

82 "summary": "Read Heroes", 

83 "operationId": "read_heroes_heroes__get", 

84 "responses": { 

85 "200": { 

86 "description": "Successful Response", 

87 "content": { 

88 "application/json": { 

89 "schema": { 

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

91 "type": "array", 

92 "items": { 

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

94 }, 

95 } 

96 } 

97 }, 

98 } 

99 }, 

100 }, 

101 "post": { 

102 "summary": "Create Hero", 

103 "operationId": "create_hero_heroes__post", 

104 "requestBody": { 

105 "content": { 

106 "application/json": { 

107 "schema": { 

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

109 } 

110 } 

111 }, 

112 "required": True, 

113 }, 

114 "responses": { 

115 "200": { 

116 "description": "Successful Response", 

117 "content": { 

118 "application/json": { 

119 "schema": { 

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

121 } 

122 } 

123 }, 

124 }, 

125 "422": { 

126 "description": "Validation Error", 

127 "content": { 

128 "application/json": { 

129 "schema": { 

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

131 } 

132 } 

133 }, 

134 }, 

135 }, 

136 }, 

137 } 

138 }, 

139 "components": { 

140 "schemas": { 

141 "HTTPValidationError": { 

142 "title": "HTTPValidationError", 

143 "type": "object", 

144 "properties": { 

145 "detail": { 

146 "title": "Detail", 

147 "type": "array", 

148 "items": { 

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

150 }, 

151 } 

152 }, 

153 }, 

154 "HeroCreate": { 

155 "title": "HeroCreate", 

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

157 "type": "object", 

158 "properties": { 

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

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

161 "age": { 

162 "title": "Age", 

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

164 }, 

165 }, 

166 }, 

167 "HeroPublic": { 

168 "title": "HeroPublic", 

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

170 "type": "object", 

171 "properties": { 

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

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

174 "age": { 

175 "title": "Age", 

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

177 }, 

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

179 }, 

180 }, 

181 "ValidationError": { 

182 "title": "ValidationError", 

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

184 "type": "object", 

185 "properties": { 

186 "loc": { 

187 "title": "Location", 

188 "type": "array", 

189 "items": { 

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

191 }, 

192 }, 

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

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

195 }, 

196 }, 

197 } 

198 }, 

199 } 

200 

201 # Test inherited indexes 

202 insp: Inspector = inspect(module.engine) 1abcdefghi

203 indexes = insp.get_indexes(str(module.Hero.__tablename__)) 1abcdefghi

204 expected_indexes = [ 1abcdefghi

205 { 

206 "name": "ix_hero_age", 

207 "dialect_options": {}, 

208 "column_names": ["age"], 

209 "unique": 0, 

210 }, 

211 { 

212 "name": "ix_hero_name", 

213 "dialect_options": {}, 

214 "column_names": ["name"], 

215 "unique": 0, 

216 }, 

217 ] 

218 for index in expected_indexes: 1abcdefghi

219 assert index in indexes, "This expected index should be in the indexes in DB" 1abcdefghi

220 # Now that this index was checked, remove it from the list of indexes 

221 indexes.pop(indexes.index(index)) 1abcdefghi

222 assert len(indexes) == 0, "The database should only have the expected indexes" 1abcdefghi