全部技能

tdd (Matt Pocock)

以測試先行的方式開發功能與修正缺陷,走紅—綠—重構循環並撰寫整合測試。

mattpocock tdd:提示詞本身就要求先寫測試時,沒有提升,Token 用量約 1.7 倍

視情況推薦安全

Codex CLI · gpt-6-astra

22.7 / 30

相對未使用技能的提升:+0.00 · 視情況推薦 · 18 次執行

視情況推薦:提升幅度 +0.00 低於 +1.0。推薦條件為總分至少 22/30、產出品質至少 3.5、提升幅度至少 +1.0。

SOTA

透過

使用 Codex 測試。

涵蓋 Codex, Claude Code

Codex CLI 0.166(SOTA 等級):18 次評分執行。依我們的等級規則,在這裡通過也涵蓋 Claude Code;但這不代表第二等級的結果。

分數

每個維度為 0 到 5 分,六個維度相加即為滿分 30 的總分。每個維度都是 5 分最好。成本 5 分代表便宜又快速;安裝 5 分代表容易安裝。

觸發可靠性
5.0
相對未使用技能的提升
2.0
產出品質
4.7
Token 與時間成本
2.0
安裝與可攜性
4.0
安全性
5.0

安全審查

安全

靜態掃描:0 CRITICAL / 0 HIGH / 0 MEDIUM。人工審查:可在無網路沙箱中安全執行(未發現問題)。掃描結果乾淨,不代表技能一定安全。

安裝

npx skills@latest add mattpocock/skills --skill tdd

來源

固定 Commit: 4ae2317ddb22b046e26455e4f9c9b3aaaf62212d

測試日期: 2026-11-02

我們測了什麼

  • 依精確規格實作一個函式 — 用 TDD 在 slug.py 中實作 slugify(text, max_length=None)(Python 3,僅限標準函式庫)。規格:將文字轉為小寫;把每一段非 ASCII 字母或數字的字元換成單一 '-';移除開頭與結尾的 '-';空結果…
  • 實作一個小型具狀態類別 — 以先寫測試(red-green-refactor)的方式撰寫 ratelimiter.py(Python 3,僅限標準函式庫),包含 class RateLimiter(limit, window_seconds, clock=time.monotonic):每個 key 的滑動視窗限流器。allow(key) 在呼叫次數少於 limit 時回傳 True 並記錄這次呼叫…
  • 修正一個四捨五入錯誤 — 客戶反映 cart.py 裡的 cart_total 有時和我們的會計系統差一分錢,會計系統在每個步驟都四捨五入到分(每個品項小計、折扣後小計、稅額)。例如 cart_total([(1.005, 1)]) 應該回傳 1.09,而…

優點

  • 技能即使未被點名也會被採用:6/6 次實驗組執行都讀取了技能檔案。
  • 使用技能後的絕對品質很高:4.67 / 5。

缺點

  • 相較未使用技能,沒有可測量的提升(+0.00,落在雜訊範圍內)。
  • 一句話提示得分 4.67,使用技能則為 4.67(+0.00)。
  • Token 用量是未使用技能的 1.7 倍。
  • 測試注意事項:一句話提示組(6 次執行)是後來在不同機器上加入的,與對照組、實驗組不同。
  • 每個任務的每個組別 n=2;約 1 分以內的差異屬於雜訊。

評測

在 Mac 測試機上使用 Codex CLI 0.166(gpt-6-astra,低推理),每次執行都建立全新的暫存專案與暫存的 HOME/TMPDIR/快取,分別安裝技能(實驗組)、未安裝技能(對照組),或未安裝技能但把技能的核心要求濃縮成一句話附在提示詞後(一句話提示組);每個任務的每個組別執行 2 次,關閉網路,封鎖 /tmp 寫入。提示詞從未提到技能(下方註明的措辭除外)。由於這個技能的描述只有在使用者要求 TDD/先寫測試時才會觸發,提示詞會明確這樣說(「using TDD」、「test-first (red-green-refactor)」、「Do it test-first」)。對照組也會收到同樣的字句,因此測試的重點是:技能能否在單純要求 TDD 的基礎上帶來改善。

三組對照

組別平均分數(0-5)每次執行 Token 用量
未使用技能4.6786k
一句話提示4.67178k
使用技能4.67146k

以 Codex CLI 執行 18 次,採規則式檢查評分,不經 LLM 評審。總分 22.7 / 30,評級為 視情況推薦。

揭露事項:一句話提示組(6 次執行)是後來才加入的,使用的機器與對照組、實驗組不同。

評定:視情況而定(22.7 / 30)。 來源:mattpocock/skills,skills/engineering/tdd,固定於提交 4ae2317。安裝:npx skills@latest add mattpocock/skills --skill tdd。授權: MIT(儲存庫 LICENSE)。

這是什麼

tdd 技能(來自 Matt Pocock 的技能儲存庫 engineering/tdd):紅綠循環,另附兩份參考檔案,說明什麼是好的測試以及何時該使用 mock。SKILL.md 約 570 字;純 Markdown,沒有腳本。當使用者想要測試先行的做法時,它就會觸發。

測試方式

在 Mac 測試機上使用 Codex CLI 0.166(gpt-6-astra,低推理),每次執行都建立全新的臨時專案,並使用臨時的 HOME/TMPDIR/快取;分別為安裝技能(技能組)、未安裝(對照組),以及未安裝但把技能核心要求濃縮成一句話附加在提示詞後(一句話組);每項任務的每組執行 2 次;關閉網路,並封鎖對 /tmp 的寫入。提示詞完全不會提到技能名稱(以下註明的措辭除外)。

由於這個技能的描述只會在使用者要求 TDD/測試先行時觸發,提示詞中會明確寫出(「使用 TDD」、「測試先行(紅綠重構)」、「以測試先行方式進行」)。對照組也會收到相同的字句,因此測試要問的是:技能是否能比單純要求 TDD 做得更好。

  1. 依精確規格實作函式 — 使用 TDD 在 slug.py 中實作 slugify(text, max_length=None)(Python 3,僅限標準函式庫)。規格:將文字轉為小寫;把每一段非 ASCII 字母或數字的字元替換成單一 '-';移除開頭與結尾的 '-';若結果為空…
  2. 實作小型有狀態類別 — 以測試先行(紅綠重構)撰寫 ratelimiter.py(Python 3,僅限標準函式庫),其中包含類別 RateLimiter(limit, window_seconds, clock=time.monotonic):為每個鍵提供滑動視窗限流器。若呼叫次數少於 limit,allow(key) 會傳回 True 並記錄該次呼叫…
  3. 修正四捨五入錯誤 — 客戶反映 cart.py 中的 cart_total 有時會與我們的會計系統相差一分錢;會計系統會在每個步驟(各品項小計、折扣後小計、稅額)以四捨五入進位到分。例如 cart_total([(1.005, 1)]) 應該傳回 1.09,而…

計分採程式化方式(隱藏測試/預埋問題召回/限制條件檢查/視情況搭配渲染與 OCR),每次執行 0–5 分。分數並非由任何 LLM 評審決定。

結果

提供給第三組的一句話版本:「以垂直切片方式測試先行:透過公開介面寫一個會失敗的測試,確認它失敗,寫最少的程式碼讓它通過,重複上述步驟,並且只在測試通過後重構;不要一次把所有測試寫完。」

任務對照組分數一句話版本技能組對照組 token 數一句話版本 token 數技能組 token 數技能讀取
t1-slugify5.05.05.079k184k135k2/2
t2-ratelimiter5.05.05.099k183k169k2/2
t3-cart-bugfix4.04.04.079k164k133k2/2

平均分數:無技能 4.67,技能組 4.67(差異 +0.0)。每次執行 token 數:86k 對 146k(1.70 倍);時間 50 秒對 67 秒。一句話組:4.67(技能相較一句話版本的增益:+0.0;一句話版本相較無技能的增益:+0.0);一句話版本每次執行 178k token,因此技能的 token 成本是一句話版本的 0.82 倍。

實際表現

  • 提示詞本身已經要求測試先行,對照組也照做了:在兩項建置任務中,兩組的每一次執行都通過所有檢查,包括「測試在實作之前撰寫」。技能在那裡沒有帶來任何可測量的增益。
  • 在錯誤修正任務(購物車四捨五入)中,無論有無技能,四次執行都修好了錯誤並通過隱藏測試,但四次都未通過同一項流程檢查:修正或測試與另一者同時出現,而不是先有一個失敗的測試。技能並未改變這一點。
  • 技能組 6/6 次執行都讀取了技能。它讓代理做了更多工作(在建置任務中 24–26 個指令,對照組為 8–10 個),結果卻相同:token 約為 1.7 倍。
  • 兩組的隱藏測試正確率都是 100%。
  • 一句話版本(以垂直切片方式測試先行,一次一個失敗測試):平均分數 4.67,與對照組和技能組相同;每次執行 178k token,對照組為 86k(2.1 倍),技能組為 146k。一句話組的代理平均每次執行跑 27 個指令,對照組為 9 個、技能組為 23 個,因為它們反覆執行測試循環。
  • 每一組在每次執行中都自行撰寫測試,且全部通過隱藏測試;三組的「測試先於實作」都在 6 次執行中達成 4 次,可見提示詞層級的「測試先行」要求,已經做到技能想達成的效果。

各面向分數

面向分數原因
1_output_quality4.67

技能組平均分數 4.67/5(程式化檢查,詳見各任務 表格)。

2_lift_vs_no_skill2.0

相較無技能的 4.67 高出 +0.00 分(每項任務 n=2;約 1 分 以下的差異屬於雜訊)。

3_trigger5.0技能組 6/6 次執行都讀取了技能檔案。
4_instructions_portability4
5_efficiency2token 為 1.70 倍(每次執行 146k 對 86k),時間為 1.34 倍(67 秒對 50 秒)。
6_safety_hygiene5

本測試的限制

  • 每則測試提示本身就要求 TDD,這讓對照組獲得了大部分好處;若使用者沒有主動要求,技能的描述根本不會觸發。
  • 只有小型 Python 任務;測試品質並未計分。
  • 每項任務的每組 n = 2:約 1 分以下的差異屬於雜訊。
  • 規則式計分只能衡量檢查項目看得見的部分,無法評判品味,也無法判斷結果是否為最佳解。

安全性

詳見 security.md。掃描:0 CRITICAL / 0 HIGH / 0 MEDIUM。評定:可在無網路沙箱中安全執行。掃描結果乾淨並不代表技能一定安全。

總結

在已經要求測試先行的前提下,這項技能對小型任務沒有額外增益:對照組、一句話版本與技能組都拿到 4.67,而技能組的 token 是對照組的 1.7 倍,一句話版本則是 2.1 倍。它或許有助於在較長的工作階段中讓測試持續聚焦於行為,但這點我們並未測量。

完整紀錄

執行日誌:tdd (Codex CLI, network off, per-run temp HOME/TMPDIR, one row per graded run.)
欄位:任務、組-輪次、得分(0-5)、token、秒、通過的檢查、代理開啟的 skill 檔案。

t1-slugify control-1: 得分 5.0, token 78904, 秒 50.3, 檢查 3/3, 未開啟
t1-slugify control-2: 得分 5.0, token 79205, 秒 47.1, 檢查 3/3, 未開啟
t1-slugify oneliner-1: 得分 5.0, token 199600, 秒 74.7, 檢查 3/3, 未開啟
t1-slugify oneliner-2: 得分 5.0, token 168650, 秒 68.2, 檢查 3/3, 未開啟
t1-slugify treatment-1: 得分 5.0, token 144538, 秒 57.6, 檢查 3/3, 開啟 tdd
t1-slugify treatment-2: 得分 5.0, token 126047, 秒 50.7, 檢查 3/3, 開啟 tdd
t2-ratelimiter control-1: 得分 5.0, token 99439, 秒 60.2, 檢查 3/3, 未開啟
t2-ratelimiter control-2: 得分 5.0, token 99611, 秒 54.3, 檢查 3/3, 未開啟
t2-ratelimiter oneliner-1: 得分 5.0, token 159969, 秒 70.9, 檢查 3/3, 未開啟

18 次執行、3 個產出檔案

範例產出

SOTA · 装了 skill:test_slug.py(t1-slugify,第 1 次,Codex)

import unittest from slug import slugify class SlugifyTests(unittest.TestCase): def test_hard_cuts_first_word_when_it_exceeds_limit(self): self.assertEqual(slugify('Supercalifragilistic', 5), 'super') def test_truncates_at_word_boundary(self): self.assertEqual(slugify('Hello, World!', 8), 'hello') def test_normalizes_text(self): self.assertEqual(slugify('Hello, World!'), 'hello-world') def test_preserves_only_ascii_letters_and_digits(self): self.assertEqual(slugify(' -- CAFÉ_42\t中文 / Test!! '), 'caf-42-test') def test_lowercases_before_filtering(self): self.assertEqual(slugify('\u212aELVIN'), 'kelvin') def test_keeps_slug_that_fits_limit(self): for limit in (11, 20, None): with self.subTest(limit=limit): self.assertEqual(slugify('Hello, World!', limit), 'hello-world') def test_keeps_complete_words_without_trailing_separator(self): for limit, expected in ((3, 'one'), (4, 'one'), (6, 'one'), (7, 'one-two'), (8, 'one-two')): with self.subTest(limit=limit): self.assertEqual(slugify('one two three', limit), expected) def test_hard_cuts_long_first_word_even_with_later_words(self): self.assertEqual(slugify('Supercalifragilistic hello', 5), 'super') def test_applies_limit_to_fallback(self): self.assertEqual(slugify('', 2), 'n') def test_empty_normalized_text_has_fallback(self): for text in ('', ' !!! ', '中文'): with self.subTest(text=text): self.assertEqual(slugify(text), 'n-a') if __name__ == '__main__': unittest.main()

檢視 Pro