Coverage for tests/test_fastapi.py: 100%
136 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 23:00 +0800
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-23 23:00 +0800
1"""測試 FastAPI 自動生成功能"""
3import pytest
4from dataclasses import dataclass
5from autocrud import AutoCRUD, MemoryStorage, FastAPIGenerator
8@dataclass
9class Product:
10 name: str
11 description: str
12 price: float
13 category: str
16class TestFastAPIGenerator:
17 """測試 FastAPI 生成器"""
19 def test_create_generator(self):
20 """測試創建 FastAPI 生成器"""
21 storage = MemoryStorage()
22 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
24 generator = FastAPIGenerator(crud)
26 assert generator.crud == crud
27 assert generator.request_model is not None
28 assert generator.response_model is not None
30 def test_request_model_fields(self):
31 """測試請求模型欄位"""
32 storage = MemoryStorage()
33 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
34 generator = FastAPIGenerator(crud)
36 request_fields = list(generator.request_model.model_fields.keys())
38 # 請求模型不應該包含 id
39 assert 'name' in request_fields
40 assert 'description' in request_fields
41 assert 'price' in request_fields
42 assert 'category' in request_fields
43 assert 'id' not in request_fields
45 def test_response_model_fields(self):
46 """測試響應模型欄位"""
47 storage = MemoryStorage()
48 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
49 generator = FastAPIGenerator(crud)
51 response_fields = list(generator.response_model.model_fields.keys())
53 # 響應模型應該包含 id
54 assert 'name' in response_fields
55 assert 'description' in response_fields
56 assert 'price' in response_fields
57 assert 'category' in response_fields
58 assert 'id' in response_fields
60 def test_create_fastapi_app(self):
61 """測試創建 FastAPI 應用"""
62 storage = MemoryStorage()
63 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
64 generator = FastAPIGenerator(crud)
66 app = generator.create_fastapi_app(
67 title="產品管理 API",
68 description="測試 API",
69 version="1.0.0"
70 )
72 assert app.title == "產品管理 API"
73 assert app.description == "測試 API"
74 assert app.version == "1.0.0"
76 def test_create_routes(self):
77 """測試創建路由"""
78 storage = MemoryStorage()
79 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
80 generator = FastAPIGenerator(crud)
82 from fastapi import FastAPI
83 app = FastAPI()
85 generator.create_routes(app, "/api/v1")
87 # 檢查路由是否已添加
88 routes = []
89 for route in app.routes:
90 if hasattr(route, 'methods') and hasattr(route, 'path'):
91 for method in route.methods:
92 if method not in ['HEAD', 'OPTIONS']:
93 routes.append(f"{method} {route.path}")
95 expected_routes = [
96 'POST /api/v1/products',
97 'GET /api/v1/products/{resource_id}',
98 'PUT /api/v1/products/{resource_id}',
99 'DELETE /api/v1/products/{resource_id}',
100 'GET /api/v1/products'
101 ]
103 for expected_route in expected_routes:
104 assert expected_route in routes
106 def test_pydantic_model_creation(self, sample_product_data):
107 """測試 Pydantic 模型創建"""
108 storage = MemoryStorage()
109 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
110 generator = FastAPIGenerator(crud)
112 # 測試請求模型
113 request_instance = generator.request_model(**sample_product_data)
114 request_dict = request_instance.model_dump()
116 assert request_dict['name'] == sample_product_data['name']
117 assert request_dict['price'] == sample_product_data['price']
119 # 測試響應模型
120 response_data = {**sample_product_data, 'id': 'test-id'}
121 response_instance = generator.response_model(**response_data)
122 response_dict = response_instance.model_dump()
124 assert response_dict['id'] == 'test-id'
125 assert response_dict['name'] == sample_product_data['name']
128class TestAutoCRUDFastAPIIntegration:
129 """測試 AutoCRUD 與 FastAPI 的整合"""
131 def test_create_fastapi_app_convenience_method(self):
132 """測試便利方法創建 FastAPI 應用"""
133 storage = MemoryStorage()
134 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
136 app = crud.create_fastapi_app(
137 title="產品 API",
138 description="便利方法創建的 API"
139 )
141 assert app.title == "產品 API"
142 assert app.description == "便利方法創建的 API"
144 def test_fastapi_app_has_health_endpoint(self):
145 """測試 FastAPI 應用包含健康檢查端點"""
146 storage = MemoryStorage()
147 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
149 app = crud.create_fastapi_app()
151 # 檢查是否有健康檢查路由
152 health_routes = []
153 for route in app.routes:
154 if hasattr(route, 'path') and route.path == '/health':
155 health_routes.append(route)
157 assert len(health_routes) > 0
159 def test_fastapi_app_has_openapi_docs(self):
160 """測試 FastAPI 應用包含 OpenAPI 文檔端點"""
161 storage = MemoryStorage()
162 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
164 app = crud.create_fastapi_app()
166 # 檢查文檔路由
167 doc_paths = []
168 for route in app.routes:
169 if hasattr(route, 'path'):
170 doc_paths.append(route.path)
172 assert '/docs' in doc_paths
173 assert '/redoc' in doc_paths
174 assert '/openapi.json' in doc_paths
177class TestFastAPIAppBehavior:
178 """測試 FastAPI 應用行為(不實際啟動服務器)"""
180 def test_app_creation_with_different_models(self):
181 """測試使用不同模型創建應用"""
182 @dataclass
183 class User:
184 name: str
185 email: str
186 age: int
188 @dataclass
189 class Book:
190 title: str
191 author: str
192 isbn: str
194 models = [
195 (User, "users"),
196 (Book, "books"),
197 (Product, "products")
198 ]
200 for model, resource_name in models:
201 storage = MemoryStorage()
202 crud = AutoCRUD(model=model, storage=storage, resource_name=resource_name)
204 app = crud.create_fastapi_app(title=f"{model.__name__} API")
206 assert app.title == f"{model.__name__} API"
208 # 檢查是否有對應的路由
209 routes = []
210 for route in app.routes:
211 if hasattr(route, 'path'):
212 routes.append(route.path)
214 assert f'/api/v1/{resource_name}' in routes
216 def test_custom_prefix_and_settings(self):
217 """測試自定義前綴和設定"""
218 storage = MemoryStorage()
219 crud = AutoCRUD(model=Product, storage=storage, resource_name="products")
220 generator = FastAPIGenerator(crud)
222 from fastapi import FastAPI
223 app = FastAPI()
225 # 使用自定義前綴
226 generator.create_routes(app, "/custom/v2")
228 routes = []
229 for route in app.routes:
230 if hasattr(route, 'path'):
231 routes.append(route.path)
233 assert '/custom/v2/products' in routes