撰寫、修改或審查任何測試程式碼時使用。依 ISTQB 測試設計技術(等價類、邊界值、決策表、狀態轉移、錯誤推測)從被測程式推出測試條件,確認每個案例都有明確的預期結果、彼此獨立,而且證明得出會紅。
Install
npx skillscat add arthurc02/skillhub/istqb-test-design Install via the SkillsCat registry.
SKILL.md
ISTQB 測試設計:測試程式碼的 SOLID
什麼時候用
- 新增或修改任何測試:單元、整合、端到端,以及測試用的 fixture 與 fake。
- 審查別人的測試 diff,或稽核既有的測試。
- 修 bug 時補回歸測試。
程序
先讀被測程式,不是先寫測試。 從產品程式列出測試條件,每一條記下它在產品程式的
檔案:行:- 分支與驗證規則把輸入分成哪幾類,含無效類(等價類);
- 每個上下限、長度、數量、大小、逾時(邊界);
- 兩個以上條件共同決定結果的地方(決策表);
- 狀態欄位與轉移函式(狀態轉移);
- 程式有處理的依賴失敗:錯誤回傳、逾時、取消、畸形輸入(錯誤推測);
- 每個對外判決依賴哪些觀察,以及那些觀察讀不到時它現在會說什麼(判決的依據)。
產品程式裡沒有的分支、上限或狀態,不是測試條件——不要自己發明需求。
寫之前先搜整個測試套件。 同一個條件常在別的檔被測過(整合測試、端到端測試);已經有了就不重複,只補缺的那一邊。
把條件落成案例,逐條對照下面十條。
證明每條新測試會紅:把它對準的那一行產品程式暫時弄壞、只跑那一條、看它失敗、改回來、確認 diff 為空(
mutation-check技能)。
修的是測試之間的依賴(T6)時例外:單改一行不會讓它紅。改用受控重現——刻意製造讓它失敗的條件,修正前紅、修正後綠,最後移除重現用的鷹架(flaky-test技能)。
十條檢查
| 準則 | 要求 | 缺陷長這樣 |
|---|---|---|
| T1 測試預言 | 每個案例斷言具體的預期結果:值、狀態、副作用、錯誤種類。預期值寫成常值,或來自被測程式以外的獨立來源(契約、規格、另一個系統的觀察);建構輸入可以用產品常數,算預期不行 | 沒有斷言;只斷言「沒出錯」或成功狀態碼,名稱講的結果沒被檢查;恆真的斷言;預期值由被測程式自己的公式、對照表、格式化函式或常數算出,或測試裡複製了一份產品規則——產品錯時兩邊一起錯,永遠綠;探針自己重組產品的鍵或路徑再斷言「不存在」,產品一改格式就恆綠 |
| T2 等價類 | 產品程式區分的每一類輸入至少一個案例 | 列舉值、驗證規則、有效/無效只測了一側 |
| T3 邊界值 | 每個限制測「界上」與「剛過界」兩點:上限 N 接受、N+1 拒絕,下限同理 | 只測遠超過上限的值,或只測被拒的那一側 |
| T4 決策表 | 多條件組合裡,每個會產生不同結果的組合都有案例 | 角色 × 擁有者 × 狀態只測了最常見的一格 |
| T5 狀態轉移 | 每個合法轉移、代表性的非法轉移、終態不可再變 | 只測快樂路徑的那一串狀態 |
| T6 獨立與可重複 | 不依賴執行順序;共享可變狀態會重置;時鐘與亂數受控;同步靠確定性訊號而不是 sleep;不打真實網路或付費服務;資源會回收 | 單獨跑綠、整套跑紅;探針查「任何」等待者而不是自己那一個 |
| T7 負面測試 | 產品程式處理的每種依賴失敗都被觸發過 | 錯誤分支只存在於程式裡,沒有任何測試走進去 |
| T10 判決的依據 | 每個對外判決(使用者看到的結論、稽核列、閘門的放行與否)都有一條「支持它的觀察讀不到」的案例,並斷言它答的是「不知道」而不是「否」或「完成」 | 觀察失敗時判決照常輸出:解碼錯誤被丟棄後零值變成一句肯定、讀不到的東西被當成不存在、少了一筆的清單被當成完整。這一條專打沒有分支的情況——錯誤被丟棄時程式裡沒有分支可測,只能從判決那一端反推 |
| T8 清楚 | 名稱寫出條件與預期結果;一個案例一個條件,表格測試的每一列有名字 | TestFoo2、it works |
| T9 假綠 | 測試不可能空跑也通過 | 迴圈跑在空集合;斷言包在 if 裡;缺環境就靜默跳過;mock 讓斷言恆真;recover() 吞掉所有 panic |
寫法
- 沿用檔案既有的慣例、helper 與 fixture;表格驅動的檔就加一列,不另起爐灶。
- fixture 裡的字串抄被測系統真正回的值,不是你以為它會回的值。
- 名稱與註解不放追蹤用的編號、日期或施工說明;為什麼要補這條測試,寫進 commit message。
- 不為了讓測試好寫而改產品程式。需要測試專用的掛鉤時,只加純新增、預設不作用的那一種,並在回報裡點名。
回報
每條新增或修改的測試一行:
<測試名稱> — <T 編號>:<條件>(產品 <檔案:行>)— 弄壞 <那一行> → FAIL(<訊息>)→ 還原 → diff 空
沒有那一次 FAIL,就不要說這條測試「補好了」。