iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
生成式 AI

打造 AI 微調平台:從系統設計到 AI 協作的 30 天實戰筆記系列 第 14

[Day 14] 測試驅動開發:從單元測試開始保障平台穩定性

  • 分享至 

  • xImage
  •  

完整程式碼可在 GitHub 專案中找到:Finetune-30-days-demo / day-14


在打造一個 AI 微調平台的過程中,我們需要不斷修改與優化系統。如果沒有測試保護,任何小小的改動都有可能破壞既有功能

前半段的開發,我刻意沒有馬上補上單元測試,因為那時候架構還在大幅變動,邊寫邊測比較快。但隨著系統漸漸穩定,今天開始我決定把單元測試補齊,並且未來每個新功能都會更重視 TDD(Test-Driven Development),讓開發過程更有防護網。


一、為什麼要 TDD?

傳統開發常見的模式是:先寫功能 → 執行 → 發現錯誤 → 臨時補測試。
TDD(Test-Driven Development)的想法是反過來:先寫測試,再實作功能

這樣的好處是:

  1. 在寫功能前就明確定義「什麼才算正確」。
  2. 測試可以作為系統的使用說明(specification)。
  3. 功能更新時,有測試可以立即驗證沒有破壞原有邏輯。

在這個過程中,我也讓 GPT 協助我快速產生測試案例,Cursor 則幫忙修改與補齊程式碼,讓測試能夠即時落地。這樣的 AI 協作方式,讓我能更快驗證平台的穩定性。


二、測試覆蓋範圍

這次我為平台建立了 兩大類測試

1. 功能測試(正常流程)

  • API 測試:提交訓練任務、查詢任務狀態(PENDING → STARTED → SUCCESS)
  • 訓練測試:驗證訓練步數是否正確遞增、耗時是否合理、準確率是否在合理區間

👉 確保核心功能「能跑得通」。

2. 錯誤與邊界情況

設計以下測試場景,避免系統在異常情況下崩潰:

  • 數據集錯誤:空資料集、缺少驗證集、無效路徑、超長序列
  • 資源錯誤:模擬 OOM、CPU/記憶體異常
  • API 錯誤:無效配置檔案、錯誤的任務 ID
  • 訓練錯誤:模擬 OOM、模擬空資料錯誤

👉 確保異常情況能被正確捕捉,而不是讓平台直接 crash。


三、測試驅動的開發流程

我的做法是:

  1. 先寫測試:定義 API 或訓練器的期望回傳格式
  2. 實作功能:讓功能能通過測試
  3. 持續重構:在測試保護下放心修改

例如 API 測試中的一段簡化程式碼:

def test_task_status(client):
    # 提交訓練任務
    response = client.post("/train", json={"config_path": "config/test.yaml"})
    task_id = response.json()["task_id"]

    # 查詢任務狀態
    status_response = client.get(f"/task/{task_id}")
    assert status_response.status_code == 200
    assert status_response.json()["status"] in ["PENDING", "STARTED", "SUCCESS"]

有了這層保護,我在修改 Celery 或 FastAPI 的邏輯時,就能確保 API 不會突然改壞。


透過這些測試,平台現在具備了基本的 穩定性:提交任務、查詢狀態、訓練流程都有測試保護;同時也涵蓋了數據錯誤與資源錯誤的模擬,避免平台在邊界情況下直接崩潰。這讓我能在後續重構與擴展功能時更有信心,不必擔心改壞舊有流程。

更重要的是,TDD 讓測試不再只是「找錯」,而是成為開發規格的一部分。對我而言,AI 協作的價值也在這裡:GPT 幫我快速生成測試範例,Cursor 實作細節,讓我可以專注在驗證設計是否正確。隨著這個測試基礎逐漸建立,平台才真正具備了「可持續優化」的能力。


📎 AI 協作記錄:今日開發指令

請幫我撰寫單元測試,新增以下檔案:
1. tests/test_api.py
   - 測試 /train 任務提交是否成功回傳 task_id
   - 測試 /task/{id} 回傳 PENDING / SUCCESS / FAILURE
   - 測試無效 task_id 與 config 缺失的錯誤處理

2. tests/test_training.py
   - 測試正常訓練流程,驗證步數與準確率
   - 測試空資料集應該拋出錯誤
   - 測試超長序列會正確截斷
   - 測試記憶體不足錯誤會被攔截

要求:
- 使用 pytest
- 對外部依賴(Celery/Redis)使用 mock
- 測試命名清晰

上一篇
[Day 13] 部署策略比較 — 用 FastAPI 部署自己的模型
下一篇
[Day 15] 系統韌性設計:錯誤回復與 Checkpoint 管理
系列文
打造 AI 微調平台:從系統設計到 AI 協作的 30 天實戰筆記15
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言