動作
Task #33
進行中PID測試腳本-登入
開始日期:
2025-09-08
完成日期:
完成百分比:
100%
預估工時:
OS版本:
Windows, Linux
網路環境:
內網
現場IP位置:
localhost
硬體設備規格:
DELLPrecision 5820 Tower intel(R)Xeon(R)w-2233 CPU,3.6GHz, RAM:128G Windows 11專業版工作站。x64位元
概述
登入系統測試 TODO 清單
測試環境準備
- 建立測試資料庫連線
- 準備測試用戶種子資料
- 設定測試環境變數(JWT_SECRET_KEY, DATABASE_URL)
- 初始化 pytest fixtures
- 準備 httpx AsyncClient 測試客戶端
一、基本登入功能測試
✅ 成功登入場景
- LOGIN-001: 使用正確的 email 和密碼成功登入
POST /api/v1/users/login
{
"email": "test@example.com",
"password": "Test@123456"
}- 驗證 HTTP 狀態碼 = 200
- 驗證響應包含 access_token
- 驗證響應包含 token_type = "bearer"
- LOGIN-002: 使用大小寫混合的 email 成功登入
{
"email": "Test@Example.COM",
"password": "Test@123456"
}- 驗證 email 大小寫不敏感
- LOGIN-003: 密碼包含特殊字符成功登入
{
"email": "test@example.com",
"password": "Test@#$%^&*()123"
} - LOGIN-004: 使用最短有效密碼長度(8字符)成功登入
- LOGIN-005: 使用最長有效密碼長度(128字符)成功登入
二、登入失敗場景測試
❌ 認證錯誤
- LOGIN-006: 錯誤密碼登入失敗
{
"email": "test@example.com",
"password": "WrongPassword123"
}- 驗證 HTTP 狀態碼 = 401
- 驗證錯誤訊息 = "用戶名或密碼錯誤"
- 驗證不返回任何 token
- LOGIN-007: 不存在的 email 登入失敗
{
"email": "notexist@example.com",
"password": "AnyPassword123"
}- 驗證 HTTP 狀態碼 = 401
- 驗證錯誤訊息 = "用戶名或密碼錯誤"(不暴露用戶是否存在)
- LOGIN-008: 密碼大小寫錯誤登入失敗
{
"email": "test@example.com",
"password": "test@123456" // 正確是 Test@123456
}
❌ 帳號狀態問題
- LOGIN-009: 未啟用帳號(is_active=false)登入失敗
- 驗證 HTTP 狀態碼 = 400
- 驗證錯誤訊息 = "用戶未啟用"
- LOGIN-010: 已刪除帳號(deleted_at 不為 null)登入失敗
- 驗證 HTTP 狀態碼 = 401
- 驗證錯誤訊息 = "用戶名或密碼錯誤"
- LOGIN-011: 帳號被鎖定(如有此功能)登入失敗
三、輸入驗證測試
📝 必填欄位驗證
- LOGIN-012: 缺少 email 欄位
{
"password": "Test@123456"
}- 驗證 HTTP 狀態碼 = 422
- 驗證錯誤訊息包含 "field required"
- LOGIN-013: 缺少 password 欄位
{
"email": "test@example.com"
}- 驗證 HTTP 狀態碼 = 422
- LOGIN-014: 完全空的請求體
{}- 驗證 HTTP 狀態碼 = 422
📝 欄位格式驗證
- LOGIN-015: 無效的 email 格式
{
"email": "not-an-email",
"password": "Test@123456"
}- 驗證 HTTP 狀態碼 = 422
- 驗證錯誤訊息包含 email 格式錯誤
- LOGIN-016: 空白 email
{
"email": "",
"password": "Test@123456"
} - LOGIN-017: 空白密碼
{
"email": "test@example.com",
"password": ""
} - LOGIN-018: email 包含空格
{
"email": " test@example.com ",
"password": "Test@123456"
}- 測試是否自動 trim 空格
- LOGIN-019: null 值作為 email
{
"email": null,
"password": "Test@123456"
} - LOGIN-020: null 值作為 password
{
"email": "test@example.com",
"password": null
}
四、JWT Token 測試
🔐 Token 生成驗證
- LOGIN-021: Token 可以成功解碼
- 使用 PyJWT 解碼 token
- 驗證 payload 包含 sub(用戶 ID)
- 驗證 payload 包含 exp(過期時間)
- LOGIN-022: Token 包含正確的用戶 ID
- 解碼 token 獲取 sub
- 查詢資料庫驗證用戶 ID 正確
- LOGIN-023: Token 過期時間設定正確
- 驗證 exp 時間 = 當前時間 + ACCESS_TOKEN_EXPIRE_MINUTES
- LOGIN-024: Token 使用正確的算法簽名(HS256)
🔐 Token 使用測試
- LOGIN-025: 使用 Token 成功訪問受保護端點
GET /api/v1/users/me
Headers: Authorization: Bearer {token}- 驗證成功返回用戶資訊
- LOGIN-026: 無 Token 訪問受保護端點失敗
GET /api/v1/users/me- 驗證 HTTP 狀態碼 = 401
- LOGIN-027: 使用過期 Token 訪問失敗
- 手動創建過期 token
- 驗證 HTTP 狀態碼 = 401
- LOGIN-028: 使用偽造 Token 訪問失敗
- 使用錯誤的 secret key 簽名
- 驗證 HTTP 狀態碼 = 401
- LOGIN-029: Token 格式錯誤(缺少 Bearer 前綴)
Headers: Authorization: {token}- 驗證 HTTP 狀態碼 = 401
- LOGIN-030: Token 格式錯誤(錯誤的前綴)
Headers: Authorization: Basic {token}
五、安全性測試
🛡️ 注入攻擊防護
- LOGIN-031: SQL 注入測試 - email 欄位
{
"email": "' OR '1'='1",
"password": "any"
}- 驗證不會繞過認證
- 驗證返回正常的錯誤訊息
- LOGIN-032: SQL 注入測試 - password 欄位
{
"email": "test@example.com",
"password": "' OR '1'='1"
} - LOGIN-033: NoSQL 注入測試(如果使用 MongoDB)
{
"email": {"$ne": null},
"password": {"$ne": null}
} - LOGIN-034: XSS 注入測試
{
"email": "<script>alert('xss')</script>@example.com",
"password": "Test@123456"
}
🛡️ 暴力破解防護
- LOGIN-035: 連續失敗登入 5 次
- 驗證是否有速率限制
- 驗證是否記錄失敗次數
- LOGIN-036: 同一 IP 短時間內大量請求
- 10 秒內發送 100 個請求
- 驗證是否觸發速率限制
- LOGIN-037: 不同用戶同時登入測試
- 並發 10 個不同用戶登入
- 驗證系統正常處理
🛡️ 密碼安全
- LOGIN-038: 錯誤密碼不洩漏密碼格式資訊
- 驗證錯誤訊息不包含「密碼太短」等提示
- LOGIN-039: 響應時間一致性(防止時序攻擊)
- 測試存在用戶錯誤密碼的響應時間
- 測試不存在用戶的響應時間
- 驗證時間差異 < 100ms
六、邊界條件測試
📊 極端輸入
- LOGIN-040: 超長 email(255 字符)
- LOGIN-041: 超長密碼(1000 字符)
- LOGIN-042: Unicode 字符在 email
{
"email": "測試@example.com",
"password": "Test@123456"
} - LOGIN-043: Emoji 在密碼中
{
"email": "test@example.com",
"password": "Test😀123456"
} - LOGIN-044: 特殊控制字符測試
{
"email": "test\n@example.com",
"password": "Test@123456"
}
七、並發與效能測試
⚡ 並發測試
- LOGIN-045: 同一用戶並發登入 10 次
- 驗證所有請求都成功
- 驗證生成不同的 token
- LOGIN-046: 100 個不同用戶同時登入
- 驗證系統穩定性
- 記錄平均響應時間
- LOGIN-047: 登入時資料庫連線池測試
- 模擬連線池滿載情況
⏱️ 效能基準
- LOGIN-048: 單次登入響應時間 < 500ms
- LOGIN-049: 1000 次登入平均響應時間 < 1s
- LOGIN-050: 記憶體使用不超過 100MB
八、錯誤處理測試
⚠️ 系統錯誤
- LOGIN-051: 資料庫連線失敗時的處理
- 模擬資料庫斷線
- 驗證返回 500 錯誤
- 驗證不洩漏系統資訊
- LOGIN-052: Redis 快取失敗時的處理(如有使用)
- LOGIN-053: JWT 密鑰缺失時的處理
⚠️ 請求格式錯誤
- LOGIN-054: Content-Type 不是 application/json
- LOGIN-055: 無效的 JSON 格式
{ email: "test@example.com" } // 缺少引號 - LOGIN-056: 請求體過大(> 1MB)
九、多因素認證測試(如有實現)
📱 2FA 測試
- LOGIN-057: 啟用 2FA 的用戶需要驗證碼
- LOGIN-058: 錯誤的 2FA 驗證碼登入失敗
- LOGIN-059: 過期的 2FA 驗證碼登入失敗
- LOGIN-060: 2FA 備用碼測試
十、審計與日誌測試
📝 日誌記錄
- LOGIN-061: 成功登入記錄到日誌
- 記錄時間、用戶 ID、IP 地址
- LOGIN-062: 失敗登入記錄到日誌
- 記錄失敗原因
- LOGIN-063: 可疑活動記錄(如 SQL 注入嘗試)
- LOGIN-064: 日誌不包含敏感資訊(密碼)
測試資料準備
基礎測試用戶
TEST_USERS = [
{
"email": "active@test.com",
"password": "Active@123456",
"is_active": True,
"role": "USER"
},
{
"email": "inactive@test.com",
"password": "Inactive@123456",
"is_active": False,
"role": "USER"
},
{
"email": "deleted@test.com",
"password": "Deleted@123456",
"deleted_at": "2024-01-01 00:00:00",
"role": "USER"
}
]
測試執行計畫
執行順序
- 環境準備(資料庫、測試資料)
- 基本功能(LOGIN-001 ~ LOGIN-005)
- 錯誤處理(LOGIN-006 ~ LOGIN-011)
- 輸入驗證(LOGIN-012 ~ LOGIN-020)
- Token 測試(LOGIN-021 ~ LOGIN-030)
- 安全測試(LOGIN-031 ~ LOGIN-039)
- 邊界測試(LOGIN-040 ~ LOGIN-044)
- 效能測試(LOGIN-045 ~ LOGIN-050)
- 系統測試(LOGIN-051 ~ LOGIN-064)
測試指標
- 功能覆蓋率:100%
- 程式碼覆蓋率:> 90%
- 安全測試:全部通過
- 效能基準:全部達標
動作