Coverage for tests/test_full_api.py: 100%

114 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-23 23:00 +0800

1"""測試完整 API 創建功能""" 

2 

3import pytest 

4from dataclasses import dataclass 

5from autocrud import AutoCRUD, MemoryStorage 

6 

7 

8@dataclass 

9class Book: 

10 title: str 

11 author: str 

12 isbn: str 

13 price: float 

14 published_year: int 

15 

16 

17class TestFullAPICreation: 

18 """測試完整的 API 創建流程""" 

19 

20 @pytest.fixture 

21 def sample_books(self): 

22 """提供測試書籍數據""" 

23 return [ 

24 { 

25 "title": "Python 程式設計", 

26 "author": "張三", 

27 "isbn": "978-1111111111", 

28 "price": 450.0, 

29 "published_year": 2023, 

30 }, 

31 { 

32 "title": "Web 開發實戰", 

33 "author": "李四", 

34 "isbn": "978-2222222222", 

35 "price": 520.0, 

36 "published_year": 2024, 

37 }, 

38 { 

39 "title": "資料結構與算法", 

40 "author": "王五", 

41 "isbn": "978-3333333333", 

42 "price": 380.0, 

43 "published_year": 2022, 

44 }, 

45 ] 

46 

47 def test_api_creation_basic(self): 

48 """測試基本 API 創建""" 

49 storage = MemoryStorage() 

50 crud = AutoCRUD(model=Book, storage=storage, resource_name="books") 

51 

52 app = crud.create_fastapi_app( 

53 title="書籍管理 API", 

54 description="自動生成的書籍 CRUD API,支援完整的圖書管理功能", 

55 version="1.0.0", 

56 ) 

57 

58 assert app.title == "書籍管理 API" 

59 assert app.description == "自動生成的書籍 CRUD API,支援完整的圖書管理功能" 

60 assert app.version == "1.0.0" 

61 

62 def test_api_routes_generation(self): 

63 """測試 API 路由生成""" 

64 storage = MemoryStorage() 

65 crud = AutoCRUD(model=Book, storage=storage, resource_name="books") 

66 

67 app = crud.create_fastapi_app() 

68 

69 # 收集所有路由 

70 routes = [] 

71 for route in app.routes: 

72 if hasattr(route, "methods") and hasattr(route, "path"): 

73 for method in route.methods: 

74 if method not in ["HEAD", "OPTIONS"]: 

75 routes.append(f"{method} {route.path}") 

76 

77 expected_routes = [ 

78 "POST /api/v1/books", 

79 "GET /api/v1/books/{resource_id}", 

80 "PUT /api/v1/books/{resource_id}", 

81 "DELETE /api/v1/books/{resource_id}", 

82 "GET /api/v1/books", 

83 ] 

84 

85 for expected_route in expected_routes: 

86 assert expected_route in routes 

87 

88 def test_api_with_preloaded_data(self, sample_books): 

89 """測試預載數據的 API""" 

90 storage = MemoryStorage() 

91 crud = AutoCRUD(model=Book, storage=storage, resource_name="books") 

92 

93 # 預填測試數據 

94 created_books = [] 

95 for book_data in sample_books: 

96 book = crud.create(book_data) 

97 created_books.append(book) 

98 

99 assert len(created_books) == 3 

100 

101 # 創建 API 

102 app = crud.create_fastapi_app( 

103 title="書籍管理 API", 

104 description="預載數據的 API" 

105 ) 

106 

107 # 驗證數據仍然存在 

108 all_books = crud.list_all() 

109 assert len(all_books) == 3 

110 

111 # 驗證每本書的數據 

112 for i, (book_id, book) in enumerate(all_books.items()): 

113 original_book = sample_books[i] 

114 assert book["title"] == original_book["title"] 

115 assert book["author"] == original_book["author"] 

116 assert book["isbn"] == original_book["isbn"] 

117 

118 def test_crud_operations_through_api_backend(self, sample_books): 

119 """測試通過 API 後端進行 CRUD 操作""" 

120 storage = MemoryStorage() 

121 crud = AutoCRUD(model=Book, storage=storage, resource_name="books") 

122 

123 # 創建 API 

124 app = crud.create_fastapi_app() 

125 

126 # 添加測試數據 

127 created_books = [] 

128 for book_data in sample_books: 

129 book = crud.create(book_data) 

130 created_books.append(book) 

131 

132 # 測試列出所有書籍 

133 all_books = crud.list_all() 

134 assert len(all_books) == 3 

135 

136 # 測試獲取特定書籍 

137 first_book_id = created_books[0]["id"] 

138 retrieved_book = crud.get(first_book_id) 

139 assert retrieved_book["title"] == sample_books[0]["title"] 

140 

141 # 測試更新書籍 

142 updated_data = { 

143 "title": "Python 高級程式設計", 

144 "author": "張三", 

145 "isbn": "978-1111111111", 

146 "price": 550.0, 

147 "published_year": 2024, 

148 } 

149 updated_book = crud.update(first_book_id, updated_data) 

150 assert updated_book["title"] == "Python 高級程式設計" 

151 assert updated_book["price"] == 550.0 

152 

153 # 測試刪除書籍 

154 last_book_id = created_books[-1]["id"] 

155 deleted = crud.delete(last_book_id) 

156 assert deleted is True 

157 

158 # 驗證最終狀態 

159 final_books = crud.list_all() 

160 assert len(final_books) == 2 # 3 - 1 = 2 

161 

162 def test_api_with_different_models(self): 

163 """測試不同模型的 API 創建""" 

164 @dataclass 

165 class Article: 

166 title: str 

167 content: str 

168 author: str 

169 published: bool 

170 

171 @dataclass 

172 class User: 

173 username: str 

174 email: str 

175 age: int 

176 

177 models = [ 

178 (Book, "books", "書籍管理 API"), 

179 (Article, "articles", "文章管理 API"), 

180 (User, "users", "用戶管理 API"), 

181 ] 

182 

183 for model, resource_name, title in models: 

184 storage = MemoryStorage() 

185 crud = AutoCRUD(model=model, storage=storage, resource_name=resource_name) 

186 

187 app = crud.create_fastapi_app(title=title) 

188 

189 assert app.title == title 

190 

191 # 檢查路由 

192 routes = [] 

193 for route in app.routes: 

194 if hasattr(route, "path"): 

195 routes.append(route.path) 

196 

197 assert f"/api/v1/{resource_name}" in routes 

198 

199 def test_api_health_and_docs_endpoints(self): 

200 """測試 API 健康檢查和文檔端點""" 

201 storage = MemoryStorage() 

202 crud = AutoCRUD(model=Book, storage=storage, resource_name="books") 

203 

204 app = crud.create_fastapi_app() 

205 

206 # 收集所有路由路徑 

207 paths = [] 

208 for route in app.routes: 

209 if hasattr(route, "path"): 

210 paths.append(route.path) 

211 

212 # 檢查標準端點 

213 assert "/health" in paths 

214 assert "/docs" in paths 

215 assert "/redoc" in paths 

216 assert "/openapi.json" in paths 

217 

218 def test_api_configuration_options(self): 

219 """測試 API 配置選項""" 

220 storage = MemoryStorage() 

221 crud = AutoCRUD(model=Book, storage=storage, resource_name="books") 

222 

223 # 測試完整配置 

224 app = crud.create_fastapi_app( 

225 title="自定義標題", 

226 description="自定義描述", 

227 version="2.1.0", 

228 prefix="/custom/v2" 

229 ) 

230 

231 assert app.title == "自定義標題" 

232 assert app.description == "自定義描述" 

233 assert app.version == "2.1.0"