實戰範例 10:為核心工具方法補上單元測試
為專案的工具方法補上單元測試,提升測試覆蓋率,並整合至 Vitest 測試框架中。
/opsx:propose/opsx:apply/opsx:archive 實戰背景
在長週期的軟體專案中,沒有測試保護的程式碼就如同沒有地基的房屋,任何一次細微的修改或重構都可能意外引入嚴重的錯誤 (Regression)。為了保障核心工具函式 (Utility Functions) 的正確性,為其撰寫完備的單元測試 (Unit Tests) 是不可或缺的防線。
本範例中,我們將為專案中負責「URL 格式化與清理」的工具函數 formatUrl.ts 補上單元測試,並整合至 Vitest 測試框架。我們將使用 OpenSpec 的 快速開發工作流 (Quick Flow) 來進行此項任務。
規格定義
本次變更計畫的 Capability 為 testing-coverage。我們預計在規格增量 (Spec Delta) 中定義以下驗收標準:
## ADDED Requirements
### Requirement: Utility function tests
The project SHALL maintain unit tests for all shared utility functions using Vitest to prevent code regressions.
#### Scenario: Url formatting edge cases
- **WHEN** formatting a raw url string with leading/trailing spaces or mixed slashes
- **THEN** the test suite SHALL verify the output is sanitized and return a canonical path format
端到端 6 輪 AI 協作紀錄
以下是 You 與 AI 助手的完整對話歷史。
── 第 1 輪:建立計畫與提案 ──
- You:
/opsx:propose "為 src/utils/formatUrl.ts 補上單元測試,使用 Vitest 框架,至少覆蓋 5 種邊界情況" - AI:
好的,已建立變更計畫
add-unit-tests-to-utils:- 建立 proposal.md: 說明為什麼要為此工具函數補上單元測試。
- 建立 specs/testing-coverage/spec.md: 新增 URL 格式化邊界情況測試的驗收情境 (Scenario)。
- 建立 tasks.md: 包含以下 3 個實作任務:
- 1.1 安裝並設定 Vitest 測試框架與執行指令
- 1.2 於
tests/formatUrl.test.ts中撰寫 5 種邊界情況測試 - 1.3 執行測試並確認覆蓋率達 100%
請執行
/opsx:apply開始實作。
── 第 2 輪:審查與微調提案 ──
- You:
這 5 種情況要包含:空字串、純斜線、重複斜線、前後空白字元、以及帶有 Query Parameter 的情況。 - AI:
好的,已使用
/opsx:update更新文件:一致性更新完成。現在您可以執行
/opsx:apply了。
── 第 3 輪:實作任務 1 (安裝與設定 Vitest) ──
- You:
/opsx:apply - AI:
Implementing: add-unit-tests-to-utils (schema: spec-driven)
正在處理任務 1/3:安裝並設定 Vitest 測試框架。
我已在專案中安裝
vitest並於package.json的 scripts 中新增test: "vitest run"命令。✓ 任務已完成。已將 tasks.md 中的任務 1.1 標記為完成。
準備好進入任務 1.2「撰寫邊界測試」了嗎?
── 第 4 輪:實作任務 2 (撰寫測試代碼) ──
- You:
繼續撰寫測試。 - AI:
Implementing: add-unit-tests-to-utils
正在處理任務 2/3:於
tests/formatUrl.test.ts中撰寫 5 種邊界情況測試。我已建立了測試檔案,針對
formatUrl進行了以下 5 種情境的 assertion 驗證:import { describe, it, expect } from 'vitest'; import { formatUrl } from '../src/utils/formatUrl'; describe('formatUrl 工具函式測試', () => { it('1. 應處理前後空白', () => { expect(formatUrl(' /path/name ')).toBe('/path/name'); }); it('2. 應處理重複斜線', () => { expect(formatUrl('///path//name')).toBe('/path/name'); }); it('3. 應處理空字串', () => { expect(formatUrl('')).toBe('/'); }); it('4. 應處理純斜線', () => { expect(formatUrl('///')).toBe('/'); }); it('5. 應保留 Query String', () => { expect(formatUrl('/path?ref=test')).toBe('/path?ref=test'); }); });✓ 任務已完成。已將任務 1.2 標記為完成。
剩下最後一個任務:執行並檢查覆蓋率。是否繼續?
── 第 5 輪:實作任務 3 (執行與檢查覆蓋率) ──
- You:
繼續執行測試。 - AI:
Implementing: add-unit-tests-to-utils
正在處理任務 3/3:執行測試並確認覆蓋率。
我已執行
pnpm run test。測試結果回報:- ✓ 5/5 test cases passed.
formatUrl.ts語句 (Statement) 與分支 (Branch) 覆蓋率均達到 100%。
✓ 任務已完成。已將任務 1.3 標記為完成。
所有任務已完成!是否執行驗證與歸檔?
── 第 6 輪:驗證與歸檔 ──
- You:
執行 verify 並歸檔。 - AI:
好的,我為您執行
/opsx:verify與/opsx:archive:- 驗證成功:測試案例完全覆蓋了
Scenario: Url formatting edge cases定義的邊界條件。 - 智慧同步:已將暫存規格合併至主規格 openspec/specs/testing-coverage/spec.md。
- 目錄歸檔:已將計畫資料夾移至
openspec/changes/archive/2026-07-14-add-unit-tests-to-utils/。
Archive Complete
變更計畫已成功歸檔!
- 驗證成功:測試案例完全覆蓋了