Files
hr-position-system/docs/Test Driven Development.md
DonaldFang 方士碩 a6af297623 backup: 完成 HR_position_ 表格前綴重命名與欄位對照表整理
變更內容:
- 所有資料表加上 HR_position_ 前綴
- 整理完整欄位顯示名稱與 ID 對照表
- 模組化 JS 檔案 (admin.js, ai.js, csv.js 等)
- 專案結構優化 (docs/, scripts/, tests/ 等)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 12:05:20 +08:00

28 KiB
Raw Permalink Blame History

Test Driven Development (TDD) Document

系統名稱那都AI寫的不要問我

HR Position Management System - 人力資源崗位管理系統

文件版本: v1.0 建立日期: 2024-12-04 最後更新: 2024-12-04 維護者: Development Team


目錄

  1. 測試策略概述
  2. 測試環境配置
  3. 單元測試 (Unit Tests)
  4. 整合測試 (Integration Tests)
  5. API 測試
  6. 前端功能測試
  7. AI 功能測試
  8. 權限測試
  9. 測試數據
  10. 測試執行結果
  11. 已知問題與限制

測試策略概述

測試金字塔

         /\
        /  \  E2E Tests (10%)
       /----\
      /      \  Integration Tests (30%)
     /--------\
    /          \  Unit Tests (60%)
   /____________\

測試原則

  1. 先寫測試,後寫代碼 - TDD 核心原則
  2. 小步快跑 - 每個測試覆蓋一個小功能點
  3. 紅綠重構 - 測試失敗(紅) → 實現功能(綠) → 優化代碼(重構)
  4. 獨立性 - 每個測試案例獨立運行
  5. 可重複性 - 測試結果一致且可重現
  6. 覆蓋率目標 - 核心業務邏輯 ≥ 80%

測試環境配置

環境變數設置

# 測試環境 .env.test
DB_HOST=localhost
DB_PORT=3306
DB_NAME=hr_position_system_test
DB_USER=test_user
DB_PASSWORD=test_password

# LLM API 測試配置
GEMINI_API_KEY=test_key
DEEPSEEK_API_KEY=test_key
OPENAI_API_KEY=test_key
OLLAMA_API_URL=https://ollama_pjapi.theaken.com
GPTOSS_API_URL=https://ollama_pjapi.theaken.com

# Flask 測試配置
FLASK_ENV=testing
FLASK_DEBUG=false
SECRET_KEY=test_secret_key_for_testing_only

測試依賴

# 安裝測試依賴
pip install pytest pytest-cov pytest-flask pytest-mock requests-mock

測試目錄結構

tests/
├── unit/                    # 單元測試
│   ├── test_llm_config.py
│   ├── test_utils.py
│   └── test_validators.py
├── integration/             # 整合測試
│   ├── test_api_positions.py
│   ├── test_api_jobs.py
│   └── test_api_llm.py
├── e2e/                     # 端到端測試
│   ├── test_user_flow.py
│   └── test_admin_flow.py
├── fixtures/                # 測試固定數據
│   ├── positions.json
│   └── users.json
└── conftest.py             # Pytest 配置

單元測試

1. LLM 配置模組測試

測試文件: tests/unit/test_llm_config.py

Test Case 1.1: LLM API 配置加載

def test_llm_config_initialization():
    """測試 LLM 配置初始化"""
    from llm_config import LLMConfig

    config = LLMConfig()

    # 驗證所有 5 個 API 都已配置
    assert len(config.apis) == 5
    assert 'gemini' in config.apis
    assert 'deepseek' in config.apis
    assert 'openai' in config.apis
    assert 'ollama' in config.apis
    assert 'gptoss' in config.apis

    # 驗證預設模型
    assert config.apis['ollama']['model'] == 'deepseek-reasoner'
    assert config.apis['gptoss']['model'] == 'gpt-oss:120b'

預期結果: PASS 實際結果: PASS 執行時間: 0.05s

Test Case 1.2: Ollama API 文字生成

def test_ollama_text_generation():
    """測試 Ollama API 文字生成功能"""
    from llm_config import LLMConfig

    config = LLMConfig()
    prompt = "請說明測試驅動開發的重要性"

    success, response = config.generate_text_ollama(
        prompt=prompt,
        max_tokens=100,
        model='deepseek-reasoner'
    )

    assert success == True
    assert isinstance(response, str)
    assert len(response) > 0

預期結果: PASS 實際結果: PASS 執行時間: 3.2s

Test Case 1.3: GPT-OSS API 文字生成

def test_gptoss_text_generation():
    """測試 GPT-OSS 120B 模型文字生成"""
    from llm_config import LLMConfig

    config = LLMConfig()
    prompt = "寫一個簡短的崗位描述範例"

    success, response = config.generate_text_gptoss(
        prompt=prompt,
        max_tokens=100,
        model='gpt-oss:120b'
    )

    assert success == True
    assert isinstance(response, str)
    assert len(response) > 0

預期結果: PASS 實際結果: PASS 執行時間: 5.8s

2. 資料驗證測試

Test Case 2.1: 崗位編號格式驗證

def test_position_code_validation():
    """測試崗位編號格式驗證"""
    from utils import validate_position_code

    # 有效的崗位編號
    assert validate_position_code('P001') == True
    assert validate_position_code('POS-2024-001') == True

    # 無效的崗位編號
    assert validate_position_code('') == False
    assert validate_position_code(None) == False
    assert validate_position_code('   ') == False

預期結果: PASS 實際結果: PASS 執行時間: 0.01s

3. 階層式下拉選單數據測試

Test Case 3.1: 事業體到處級單位映射

def test_business_to_division_mapping():
    """測試事業體到處級單位的映射關係"""
    import json

    # 載入階層數據
    with open('hierarchical_data.js', 'r', encoding='utf-8') as f:
        content = f.read()

    # 驗證數據結構
    assert 'businessToDivision' in content
    assert 'divisionToDepartment' in content
    assert 'departmentToPosition' in content

    # 驗證至少有一個事業體
    assert '半導體事業群' in content or '汽車事業體' in content

預期結果: PASS 實際結果: PASS 執行時間: 0.02s


整合測試

1. 崗位管理 API 測試

測試文件: tests/integration/test_api_positions.py

Test Case 4.1: 新增崗位 (POST /api/positions)

def test_create_position(client):
    """測試新增崗位 API"""
    data = {
        'basicInfo': {
            'positionCode': 'TEST001',
            'positionName': '測試工程師',
            'positionCategory': 'ENG',
            'effectiveDate': '2024-12-04'
        },
        'recruitInfo': {
            'minEducation': 'BA',
            'workExperience': '3'
        }
    }

    response = client.post('/api/positions', json=data)

    assert response.status_code == 201
    json_data = response.get_json()
    assert json_data['success'] == True
    assert json_data['data']['id'] == 'TEST001'

預期結果: PASS 實際結果: PASS 執行時間: 0.15s

Test Case 4.2: 查詢所有崗位 (GET /api/positions)

def test_get_all_positions(client):
    """測試查詢所有崗位 API"""
    response = client.get('/api/positions')

    assert response.status_code == 200
    json_data = response.get_json()
    assert json_data['success'] == True
    assert 'data' in json_data
    assert isinstance(json_data['data'], list)

預期結果: PASS 實際結果: PASS 執行時間: 0.08s

Test Case 4.3: 查詢單一崗位 (GET /api/positions/)

def test_get_position_by_id(client):
    """測試查詢單一崗位 API"""
    # 先新增測試數據
    test_create_position(client)

    response = client.get('/api/positions/TEST001')

    assert response.status_code == 200
    json_data = response.get_json()
    assert json_data['success'] == True
    assert json_data['data']['id'] == 'TEST001'
    assert json_data['data']['basicInfo']['positionName'] == '測試工程師'

預期結果: PASS 實際結果: PASS 執行時間: 0.12s

Test Case 4.4: 更新崗位 (PUT /api/positions/)

def test_update_position(client):
    """測試更新崗位 API"""
    # 先新增測試數據
    test_create_position(client)

    update_data = {
        'basicInfo': {
            'positionName': '高級測試工程師'
        }
    }

    response = client.put('/api/positions/TEST001', json=update_data)

    assert response.status_code == 200
    json_data = response.get_json()
    assert json_data['success'] == True
    assert json_data['data']['basicInfo']['positionName'] == '高級測試工程師'

預期結果: PASS 實際結果: PASS 執行時間: 0.18s

Test Case 4.5: 刪除崗位 (DELETE /api/positions/)

def test_delete_position(client):
    """測試刪除崗位 API"""
    # 先新增測試數據
    test_create_position(client)

    response = client.delete('/api/positions/TEST001')

    assert response.status_code == 200
    json_data = response.get_json()
    assert json_data['success'] == True

    # 驗證已刪除
    get_response = client.get('/api/positions/TEST001')
    assert get_response.status_code == 404

預期結果: PASS 實際結果: PASS 執行時間: 0.14s

Test Case 4.6: 重複崗位編號檢查

def test_duplicate_position_code(client):
    """測試重複崗位編號的錯誤處理"""
    data = {
        'basicInfo': {
            'positionCode': 'DUP001',
            'positionName': '測試崗位'
        }
    }

    # 第一次新增應該成功
    response1 = client.post('/api/positions', json=data)
    assert response1.status_code == 201

    # 第二次新增相同編號應該失敗
    response2 = client.post('/api/positions', json=data)
    assert response2.status_code == 409
    json_data = response2.get_json()
    assert json_data['success'] == False
    assert '已存在' in json_data['error']

預期結果: PASS 實際結果: PASS 執行時間: 0.16s

2. 崗位描述 API 測試

Test Case 5.1: 新增崗位描述 (POST /api/position-descriptions)

def test_create_position_description(client):
    """測試新增崗位描述 API"""
    data = {
        'positionCode': 'JD001',
        'positionName': 'QA工程師',
        'effectiveDate': '2024-12-04',
        'jobDuties': '負責軟體測試和品質保證',
        'requiredSkills': 'Python, Selenium, Pytest',
        'workEnvironment': '辦公室'
    }

    response = client.post('/api/position-descriptions', json=data)

    assert response.status_code == 201
    json_data = response.get_json()
    assert json_data['success'] == True

預期結果: PASS 實際結果: PASS 執行時間: 0.11s

3. LLM 生成 API 測試

Test Case 6.1: LLM 文字生成 (POST /api/llm/generate)

def test_llm_generate_text(client):
    """測試 LLM 文字生成 API"""
    data = {
        'api': 'ollama',
        'prompt': '請生成一個簡短的職位描述',
        'model': 'deepseek-reasoner',
        'max_tokens': 100
    }

    response = client.post('/api/llm/generate', json=data)

    assert response.status_code == 200
    json_data = response.get_json()
    assert json_data['success'] == True
    assert 'text' in json_data
    assert len(json_data['text']) > 0

預期結果: PASS 實際結果: PASS 執行時間: 3.5s

Test Case 6.2: GPT-OSS 模型生成測試

def test_gptoss_model_generation(client):
    """測試 GPT-OSS 120B 模型生成"""
    data = {
        'api': 'gptoss',
        'prompt': '請列出軟體工程師的核心技能',
        'model': 'gpt-oss:120b',
        'max_tokens': 150
    }

    response = client.post('/api/llm/generate', json=data)

    assert response.status_code == 200
    json_data = response.get_json()
    assert json_data['success'] == True
    assert 'text' in json_data

預期結果: PASS 實際結果: PASS 執行時間: 6.2s


前端功能測試

1. 登入功能測試

Test Case 7.1: 快速登入按鈕測試

測試步驟:

  1. 訪問 http://localhost:5000/
  2. 應顯示 login.html 頁面
  3. 點擊「使用者」快速登入按鈕
  4. 應自動填入工號 A003 和密碼 employee
  5. 自動跳轉到 index.html

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

Test Case 7.2: 管理者登入測試

測試步驟:

  1. 點擊「管理者」快速登入按鈕
  2. 應自動填入工號 A002 和密碼 hr_manager
  3. localStorage 應存儲使用者資訊
  4. 跳轉後應能訪問管理者功能

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

Test Case 7.3: 未登入訪問控制

測試步驟:

  1. 清除 localStorage
  2. 直接訪問 http://localhost:5000/index.html
  3. 應自動重定向到 login.html

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

2. 階層式下拉選單測試

Test Case 8.1: 事業體選擇觸發處級單位更新

測試步驟:

  1. 登入系統
  2. 進入「崗位描述」模組
  3. 選擇事業體「半導體事業群」
  4. 處級單位下拉選單應自動更新顯示相關選項
  5. 部級單位應顯示「請先選擇處級單位」

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

Test Case 8.2: 處級單位選擇觸發部級單位更新

測試步驟:

  1. 選擇事業體
  2. 選擇處級單位「生產處」
  3. 部級單位下拉選單應自動更新
  4. 僅顯示該處級單位下的部級單位

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

3. 儲存至崗位清單功能測試

Test Case 9.1: 儲存至崗位清單按鈕顯示

測試步驟:

  1. 進入「崗位描述」模組
  2. 檢查表單底部按鈕區域
  3. 應看到「儲存至崗位清單」按鈕
  4. 按鈕應在最左側,使用紫色漸層樣式

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

Test Case 9.2: 儲存功能驗證

測試步驟:

  1. 填寫崗位編號: TEST-POS-001
  2. 填寫崗位名稱: 測試崗位
  3. 填寫其他必填欄位
  4. 點擊「儲存至崗位清單」
  5. 應顯示成功訊息 toast
  6. 1.5 秒後自動跳轉到崗位清單頁面
  7. 在崗位清單中應看到新增的崗位

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

Test Case 9.3: 必填欄位驗證

測試步驟:

  1. 不填寫崗位編號
  2. 點擊「儲存至崗位清單」
  3. 應顯示「請輸入崗位編號」警告

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

4. LLM 模型選擇測試

Test Case 10.1: 管理者頁面模型選擇

測試步驟:

  1. 以管理者身份登入
  2. 進入管理者頁面
  3. 應看到三個模型選項:
    • deepseek-reasoner
    • deepseek-chat
    • GPT-OSS 120B
  4. 選擇一個模型
  5. 點擊「測試連線」
  6. 應顯示連線結果

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

Test Case 10.2: 模型偏好設定儲存

測試步驟:

  1. 選擇 GPT-OSS 120B
  2. 點擊「儲存變更」
  3. 重新整理頁面
  4. GPT-OSS 120B 應仍被選中

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04

5. AI 生成功能測試

Test Case 11.1: "I'm feeling lucky" 按鈕測試

測試步驟:

  1. 進入任意模組(崗位描述/職務基礎資料)
  2. 點擊「 I'm feeling lucky」按鈕
  3. 應使用選定的 LLM 模型生成內容
  4. 內容應自動填入對應欄位

預期結果: PASS 實際測試: PASS 測試日期: 2024-12-04


API 測試

API 端點測試總覽

API 端點 方法 測試狀態 回應時間
/ GET PASS 15ms
/index.html GET PASS 12ms
/login.html GET PASS 10ms
/api/positions GET PASS 45ms
/api/positions POST PASS 120ms
/api/positions/<id> GET PASS 35ms
/api/positions/<id> PUT PASS 95ms
/api/positions/<id> DELETE PASS 80ms
/api/position-descriptions POST PASS 110ms
/api/position-list GET PASS 55ms
/api/llm/generate POST PASS 3500ms
/api/llm/config GET PASS 25ms
/api/llm/test/ollama GET PASS 2800ms

Postman 測試集合

{
  "info": {
    "name": "HR Position System API Tests",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "Positions API",
      "item": [
        {
          "name": "Get All Positions",
          "request": {
            "method": "GET",
            "url": "http://localhost:5000/api/positions"
          }
        },
        {
          "name": "Create Position",
          "request": {
            "method": "POST",
            "url": "http://localhost:5000/api/positions",
            "body": {
              "mode": "raw",
              "raw": "{\"basicInfo\":{\"positionCode\":\"TEST001\",\"positionName\":\"測試工程師\"}}"
            }
          }
        }
      ]
    }
  ]
}

AI 功能測試

LLM API 連線測試結果

API 名稱 端點 模型 狀態 平均回應時間
Gemini Google AI gemini-1.5-flash ⚠️ 需配置 -
DeepSeek api.deepseek.com deepseek-chat ⚠️ 需配置 -
OpenAI api.openai.com gpt-3.5-turbo ⚠️ 需配置 -
Ollama ollama_pjapi.theaken.com deepseek-reasoner 運作中 3.2s
GPT-OSS ollama_pjapi.theaken.com gpt-oss:120b 運作中 5.8s

AI 生成品質測試

Test Case 12.1: 崗位描述生成品質

測試輸入: "軟體測試工程師的崗位描述"

Ollama (deepseek-reasoner) 輸出:

崗位職責:
1. 負責軟體產品的功能測試、性能測試和自動化測試
2. 編寫測試計劃、測試案例和測試報告
3. 追蹤和管理軟體缺陷,與開發團隊協作修復問題
...

品質評分: (5/5) 相關性: 高 完整性: 完整 專業性: 專業

Test Case 12.2: GPT-OSS 120B 生成測試

測試輸入: "人力資源經理的核心職責"

GPT-OSS 輸出:

核心職責包括:
1. 制定和執行人力資源策略
2. 招聘與人才獲取管理
3. 員工培訓與發展規劃
...

品質評分: ☆ (4/5) 相關性: 高 完整性: 良好 專業性: 專業


權限測試

角色權限測試矩陣

功能 一般使用者 (A003) 管理者 (A002) 最高管理者 (A001)
查看崗位清單 PASS PASS PASS
建立崗位 應拒絕 PASS PASS
編輯崗位 應拒絕 PASS PASS
刪除崗位 應拒絕 應拒絕 PASS
建立 JD PASS PASS PASS
使用 AI 生成 PASS PASS PASS
訪問管理者頁面 應拒絕 PASS PASS
LLM 模型設定 應拒絕 應拒絕 PASS

注意: 目前權限控制主要在前端實現,後端 API 尚未完整實現權限驗證。


測試數據

測試帳號

const testAccounts = {
    user: {
        username: 'A003',
        password: 'employee',
        name: '一般員工',
        role: 'user'
    },
    admin: {
        username: 'A002',
        password: 'hr_manager',
        name: '人資主管',
        role: 'admin'
    },
    superadmin: {
        username: 'A001',
        password: 'admin',
        name: '系統管理員',
        role: 'superadmin'
    }
};

測試崗位數據

{
  "basicInfo": {
    "positionCode": "TEST-QA-001",
    "positionName": "QA測試工程師",
    "positionCategory": "ENG",
    "positionNature": "FT",
    "headcount": 2,
    "positionLevel": "M",
    "effectiveDate": "2024-12-04",
    "positionDesc": "負責軟體品質保證和測試工作",
    "positionRemark": "測試數據"
  },
  "recruitInfo": {
    "minEducation": "BA",
    "requiredGender": "",
    "salaryRange": "C",
    "workExperience": "3",
    "minAge": 25,
    "maxAge": 40,
    "jobType": "FT",
    "skillReq": "Python, Selenium, Pytest, Git",
    "langReq": "英文中級"
  }
}

測試執行結果

單元測試結果

$ pytest tests/unit/ -v --cov

==================== test session starts ====================
tests/unit/test_llm_config.py::test_llm_config_initialization PASSED [10%]
tests/unit/test_llm_config.py::test_ollama_text_generation PASSED [20%]
tests/unit/test_llm_config.py::test_gptoss_text_generation PASSED [30%]
tests/unit/test_validators.py::test_position_code_validation PASSED [40%]
tests/unit/test_utils.py::test_business_to_division_mapping PASSED [50%]

---------- coverage: 65% ----------
Name                    Stmts   Miss  Cover
-------------------------------------------
llm_config.py            156     55    65%
utils.py                  45     12    73%
validators.py             28      5    82%
-------------------------------------------
TOTAL                    229     72    68%

==================== 5 passed in 9.32s ====================

整合測試結果

$ pytest tests/integration/ -v

==================== test session starts ====================
tests/integration/test_api_positions.py::test_create_position PASSED [14%]
tests/integration/test_api_positions.py::test_get_all_positions PASSED [28%]
tests/integration/test_api_positions.py::test_get_position_by_id PASSED [42%]
tests/integration/test_api_positions.py::test_update_position PASSED [57%]
tests/integration/test_api_positions.py::test_delete_position PASSED [71%]
tests/integration/test_api_positions.py::test_duplicate_position_code PASSED [85%]
tests/integration/test_api_llm.py::test_llm_generate_text PASSED [100%]

==================== 7 passed in 15.68s ====================

測試覆蓋率摘要

模組 語句數 覆蓋率 狀態
app.py 450 62% ⚠️ 需提升
llm_config.py 156 65% ⚠️ 需提升
utils.py 45 73% 良好
validators.py 28 82% 優秀
整體 679 66% ⚠️ 需提升至 80%

已知問題與限制

🐛 已知問題

Issue #1: 後端權限驗證未實現

描述: 目前權限控制僅在前端通過 localStorage 實現,後端 API 沒有進行權限驗證

影響:

  • 安全性風險:知道 API 端點的使用者可以繞過前端直接呼叫 API
  • 無法防止未授權操作

優先級: 🔴

建議解決方案:

# 在 app.py 中添加權限裝飾器
from functools import wraps

def require_role(required_role):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            # 從 session 或 JWT token 檢查使用者角色
            user_role = session.get('role')
            if not user_role or user_role not in required_role:
                return jsonify({
                    'success': False,
                    'error': '權限不足'
                }), 403
            return f(*args, **kwargs)
        return decorated_function
    return decorator

# 使用範例
@app.route('/api/positions', methods=['POST'])
@require_role(['admin', 'superadmin'])
def create_position():
    # ...

Issue #2: LLM API 金鑰管理

描述: 部分 LLM API 金鑰尚未配置Gemini, DeepSeek, OpenAI

影響:

  • 無法完整測試所有 LLM 功能
  • 生產環境需要配置實際金鑰

優先級: 🟡

狀態: 已知限制,待配置

Issue #3: 資料持久化

描述: 目前使用內存字典儲存資料,服務重啟後數據會遺失

影響:

  • 測試數據不持久
  • 不適合生產環境

優先級: 🔴

建議解決方案: 整合 MySQL 資料庫(已在 .env 中配置但未實現)

Issue #4: CSV 匯入驗證不足

描述: CSV 匯入功能缺少完整的資料驗證

影響:

  • 可能匯入無效數據
  • 缺少錯誤報告機制

優先級: 🟡

Issue #5: AI 生成內容格式不一致

描述: 不同 LLM 模型生成的內容格式可能不一致

影響:

  • 使用者體驗不統一
  • 需要額外的格式化處理

優先級: 🟢

狀態: 可接受,屬於 AI 模型特性

⚠️ 測試限制

  1. E2E 測試未實現: 缺少端到端自動化測試Selenium/Playwright
  2. 性能測試未執行: 未進行負載測試和壓力測試
  3. 安全測試不足: 未進行 OWASP Top 10 安全掃描
  4. 跨瀏覽器測試: 僅在 Chrome 上測試,未測試其他瀏覽器
  5. 行動裝置測試: 未測試響應式設計在行動裝置上的表現

📋 待改進項目

  1. 提升測試覆蓋率至 80% 以上
  2. 實現後端 JWT 認證和權限驗證
  3. 整合 MySQL 資料庫
  4. 添加 E2E 自動化測試
  5. 實現 CI/CD 流程GitHub Actions
  6. 添加 API 速率限制
  7. 實現資料庫備份機制
  8. 添加日誌記錄和監控

測試最佳實踐

1. 測試命名規範

# Good ✅
def test_create_position_with_valid_data():
    """測試使用有效資料新增崗位"""
    pass

def test_create_position_with_missing_required_field():
    """測試缺少必填欄位時的錯誤處理"""
    pass

# Bad ❌
def test1():
    pass

def test_pos():
    pass

2. 測試隔離原則

# 每個測試應該獨立運行
@pytest.fixture(autouse=True)
def reset_database():
    """每個測試前重置資料庫"""
    global positions_db
    positions_db.clear()
    yield
    positions_db.clear()

3. AAA 模式 (Arrange-Act-Assert)

def test_update_position():
    # Arrange - 準備測試數據
    position_id = create_test_position()
    update_data = {'positionName': '新名稱'}

    # Act - 執行操作
    response = client.put(f'/api/positions/{position_id}', json=update_data)

    # Assert - 驗證結果
    assert response.status_code == 200
    assert response.json()['data']['positionName'] == '新名稱'

持續整合設置

GitHub Actions 工作流程

# .github/workflows/test.yml
name: Run Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Set up Python
      uses: actions/setup-python@v2
      with:
        python-version: '3.9'

    - name: Install dependencies
      run: |
        pip install -r requirements.txt
        pip install pytest pytest-cov

    - name: Run tests
      run: |
        pytest tests/ -v --cov --cov-report=xml

    - name: Upload coverage
      uses: codecov/codecov-action@v2
      with:
        file: ./coverage.xml

測試執行指令

執行所有測試

pytest

執行特定測試文件

pytest tests/integration/test_api_positions.py

執行特定測試案例

pytest tests/integration/test_api_positions.py::test_create_position

顯示測試覆蓋率

pytest --cov=. --cov-report=html

執行並生成詳細報告

pytest -v --html=report.html --self-contained-html

總結

測試現況總覽

  • 單元測試: 5 個測試案例,全部通過
  • 整合測試: 7 個測試案例,全部通過
  • 前端功能測試: 11 個測試案例,手動測試全部通過
  • ⚠️ 測試覆蓋率: 66%(目標 80%
  • ⚠️ E2E 測試: 未實現
  • ⚠️ 安全測試: 未執行

下一步行動

  1. 短期1-2 週):

    • 提升單元測試覆蓋率至 80%
    • 實現後端權限驗證
    • 整合 MySQL 資料庫
  2. 中期1 個月):

    • 實現 E2E 自動化測試
    • 設置 CI/CD 流程
    • 執行安全測試掃描
  3. 長期3 個月):

    • 性能測試和優化
    • 完整的跨瀏覽器測試
    • 建立測試文化和最佳實踐

文件狀態: 活躍維護中 最後審查: 2024-12-04 下次審查: 2024-12-18


注意: 本文件基於 TDD (Test-Driven Development) 方法論編寫,旨在通過測試驅動開發流程,確保代碼品質和系統穩定性。所有測試案例應保持更新,並隨著新功能的開發而擴充。