「前端寫好了,後端也測試通過了,為什麼整合起來就是不能動?」
資深工程師微笑著說:「你有測試過前後端的合作默契嗎?」
經過 27 天的旅程,我們已經具備了扎實的測試基礎。今天,我們要為即將到來的前後端整合做準備。
tests/integration/test_health_check.py
:import pytest
from typing import Dict, Any
def test_verify_all_api_endpoints_are_working(client):
"""驗證所有 API 端點正常運作"""
# GET /api/todos
response = client.get('/api/todos')
assert response.status_code == 200
data = response.json()
assert 'data' in data
# POST /api/todos
response = client.post('/api/todos', json={'title': 'Test Todo'})
assert response.status_code == 201
todo_id = response.json()['data']['id']
# PATCH /api/todos/{id}
response = client.patch(f'/api/todos/{todo_id}', json={'completed': True})
assert response.status_code == 200
assert response.json()['data']['completed'] is True
# DELETE /api/todos/{id}
response = client.delete(f'/api/todos/{todo_id}')
assert response.status_code == 204
def test_api_responses_follow_consistent_format(client, sample_todo):
"""API 回應格式一致性測試"""
response = client.get('/api/todos')
data = response.json()
assert 'data' in data
assert 'meta' in data
assert 'total' in data['meta']
def test_error_responses_have_consistent_structure(client):
"""錯誤回應結構一致性測試"""
response = client.post('/api/todos', json={})
assert response.status_code == 422
error_data = response.json()
assert 'detail' in error_data
tests/integration/test_cors.py
:def test_cors_headers_are_present(client):
"""CORS 標頭測試"""
response = client.options(
'/api/todos',
headers={
'Origin': 'http://localhost:3000',
'Access-Control-Request-Method': 'GET'
}
)
assert 'access-control-allow-origin' in response.headers
assert 'access-control-allow-methods' in response.headers
def test_preflight_requests_work_correctly(client):
"""預檢請求測試"""
response = client.options(
'/api/todos',
headers={
'Origin': 'http://localhost:3000',
'Access-Control-Request-Method': 'POST',
'Access-Control-Request-Headers': 'Content-Type'
}
)
assert response.status_code == 200
assert 'access-control-allow-headers' in response.headers
tests/integration/test_authentication.py
:import jwt
from datetime import datetime, timedelta
def test_authenticated_requests_work(client, auth_headers):
"""測試已認證的請求"""
response = client.get('/api/user', headers=auth_headers)
assert response.status_code == 200
user_data = response.json()
assert 'id' in user_data
def test_unauthenticated_requests_are_rejected(client):
"""測試未認證的請求被拒絕"""
response = client.get('/api/user')
assert response.status_code == 401
def test_token_based_auth_works(client, test_user):
"""測試 Token 認證機制"""
response = client.post('/api/auth/login', json={
'email': test_user['email'],
'password': test_user['password']
})
assert response.status_code == 200
token = response.json()['access_token']
response = client.get('/api/user', headers={'Authorization': f'Bearer {token}'})
assert response.status_code == 200
tests/integration/test_validation_boundaries.py
:def test_validates_string_length_limits(client):
"""測試字串長度限制"""
long_string = 'a' * 256
response = client.post('/api/todos', json={'title': long_string})
assert response.status_code == 422
def test_validates_special_characters(client):
"""測試特殊字符處理"""
special_chars = '<script>alert("XSS")</script>'
response = client.post('/api/todos', json={'title': special_chars})
assert response.status_code == 201
assert response.json()['data']['title'] == special_chars
def test_validates_unicode_characters(client):
"""測試 Unicode 字符處理"""
unicode_title = '測試 📝 テスト 🎯'
response = client.post('/api/todos', json={'title': unicode_title})
assert response.status_code == 201
assert response.json()['data']['title'] == unicode_title
tests/integration/test_performance.py
:import time
from concurrent.futures import ThreadPoolExecutor
def test_api_response_time_is_acceptable(client, sample_todos):
"""測試 API 回應時間"""
start_time = time.time()
response = client.get('/api/todos')
duration = (time.time() - start_time) * 1000
assert response.status_code == 200
assert duration < 100 # 應該在 100ms 內回應
def test_handles_concurrent_requests(client):
"""測試並發請求處理"""
def create_todo(index):
return client.post('/api/todos', json={'title': f'Concurrent Todo {index}'})
with ThreadPoolExecutor(max_workers=5) as executor:
futures = [executor.submit(create_todo, i) for i in range(5)]
responses = [f.result() for f in futures]
for response in responses:
assert response.status_code == 201
tests/integration/test_error_recovery.py
:def test_handles_malformed_json_requests(client):
"""測試處理格式錯誤的 JSON 請求"""
response = client.post(
'/api/todos',
data='{invalid json}',
headers={'Content-Type': 'application/json'}
)
assert response.status_code == 400
assert 'detail' in response.json()
def test_handles_missing_endpoints(client):
"""測試處理不存在的端點"""
response = client.get('/api/nonexistent')
assert response.status_code == 404
def test_handles_method_not_allowed(client):
"""測試處理不允許的 HTTP 方法"""
response = client.put('/api/todos')
assert response.status_code == 405
src/services/integration_checker.py
:from typing import Dict, List
import asyncio
from datetime import datetime
class IntegrationChecker:
"""整合環境檢查器"""
def __init__(self):
self.checks: Dict[str, bool] = {}
self.check_results: List[Dict] = []
async def check_database(self) -> bool:
"""檢查資料庫連接"""
try:
# 實際的資料庫連接檢查
self.checks['database'] = True
return True
except Exception as e:
self.checks['database'] = False
self._log_check('database', False, str(e))
return False
async def check_cache(self) -> bool:
"""檢查快取服務"""
try:
self.checks['cache'] = True
return True
except Exception as e:
self.checks['cache'] = False
self._log_check('cache', False, str(e))
return False
async def run_all_checks(self) -> Dict[str, bool]:
"""執行所有檢查"""
tasks = [
self.check_database(),
self.check_cache()
]
await asyncio.gather(*tasks)
return self.checks
def _log_check(self, name: str, success: bool, error: str = None):
"""記錄檢查結果"""
self.check_results.append({
'name': name,
'success': success,
'error': error,
'timestamp': datetime.utcnow().isoformat()
})
def get_health_status(self) -> Dict:
"""獲取健康狀態摘要"""
all_checks_pass = all(self.checks.values())
return {
'healthy': all_checks_pass,
'checks': self.checks,
'timestamp': datetime.utcnow().isoformat()
}
✅ 建立完整的 API 端點健康檢查
✅ 設定並測試 CORS 配置
✅ 準備認證與授權基礎設施
✅ 實作資料驗證邊界測試
✅ 建立效能基準測試
✅ 測試錯誤恢復機制
✅ 實作整合檢查服務
今天我們為前後端整合做了充分的準備:
明天我們將把這些準備工作付諸實踐,完成前後端的整合測試!🚀