iT邦幫忙

2026 iThome 鐵人賽

DAY 25
0

Day 24 最後留了一個很明確的方向:

Day 25 我想給它補 focused unit coverage:每個條件單獨壞一次,看它自己能不能讓整個判斷不通過。

這個「它」,就是決定 產生 Project Specification 能不能按的函式:

isSpecificationSetupComplete()

所以今天不再補 browser test,往下一層補它的 focused unit coverage。

ClarifyBuild 是我這系列正在做的小工具:它會把一個模糊的產品 idea,透過幾站釐清流程,整理成 Project Specification,最後再組成 AI Coding Prompt。

今天新增的是一條 unit test,裡面用迴圈跑 17 個 case。

結果是:npm test 31 條全過,30 條舊的,加今天這 1 條。

產品程式沒有改。

今天做的事,是把既有完成條件釘得更清楚。


Browser test 守住結果

Day 23 和 Day 24 其實已經守住了使用者看得到的結果。

起點 動作 守住的結果
Day 23 四個 setup 區塊都沒做 一塊一塊儲存 四塊都完成前,產生 Project Specification 保持 disabled
Day 24 四塊都完成 把主要使用者改成「研究生與助教」 主要流程、技術設定變成「需要重新檢查」,功能規格掉到 0 / 1,功能規格標題顯示「需要重新檢查」,按鈕重新鎖住

這兩條 browser test 的起點 draft 是預先放進 localStorage 的。

但起點之後,每一步都是點按鈕、填欄位、讀畫面。

所以它們守的是 main.js、scopeEngine.js、render.js 接起來之後的結果。

這很重要。

因為使用者不會看到某個函式回傳 true 或 false。

使用者只會看到:

我現在可不可以產生 Project Specification?

Day 23 和 Day 24 的答案是:

不完整不能產生,資料過期也不能產生。


今天要拆開條件

Browser test 很適合守「最後有沒有被擋住」。

但它不適合回答:

到底是哪個條件在擋?

Day 24 的 browser test 裡,需求一改,主要流程、功能規格、技術設定會一起變成需要重新檢查。

按鈕 disabled。

但那條測試只能說明「至少有一個條件讓它不能產生」。

例如這幾個問題,browser test 不適合一個一個回答:

  • 只有 flow needsReview,會不會擋?
  • 只有 feature spec 的 basedOnRevision 過期,會不會擋?
  • 只有 tech stack needsReview,會不會擋?
  • 只有 specified tech 沒填 items,會不會擋?

這些條件如果只靠一條 browser flow,很難知道是哪個條件真的有被獨立守住。

這就是 Day 25 要補的空洞。

不是再走一次畫面流程。

而是直接問核心判斷:

isSpecificationSetupComplete(draft)

只要 draft 裡某個必要條件壞掉,這個函式就必須回傳 false。


每次只破壞一個條件

今天新增的測試叫:

specification setup completeness fails when any required setup condition is missing

它的測法很單純。

先建立一份完整的 Specification Setup draft。

這份 draft 有:

  • 一個 Must Have 功能
  • 一個主要流程步驟
  • 一份完整 feature specification
  • 已 review 的 project constraints
  • ai_delegated 的 tech stack,也就是交給 Coding Agent 選技術
  • 所有 needsReview 都是 false

測試先確認它真的完整:

isSpecificationSetupComplete(completeSpecificationDraft()) === true

接著每個 case 都重新建立一份乾淨的完整 draft。

然後只破壞一個條件。

最後確認:

isSpecificationSetupComplete(draft) === false

程式大概長這樣:

const cases = [
  {
    name: "flow needsReview",
    breakDraft(draft) {
      draft.targetProjectUserFlow.needsReview = true;
    }
  },
  {
    name: "tech needsReview",
    breakDraft(draft) {
      draft.buildConfig.techStack.needsReview = true;
    }
  }
  // ...共 17 個
];

cases.forEach(({ name, breakDraft }) => {
  const draft = completeSpecificationDraft();
  breakDraft(draft);
  assert.equal(isSpecificationSetupComplete(draft), false, name);
});

這樣做的好處是:測試訊息會指向第一個壞掉的 case 名稱。

它仍然是一條 test,不是 17 條 test。

但當某個條件被意外放寬時,失敗訊息至少不會只剩「整個流程怪怪的」。

它會告訴我,是哪個 focused case 沒守住。


今天釘住哪些條件

isSpecificationSetupComplete() 現在要求四個 setup section 都完整,而且不能過期。

Day 25 把這些條件拆成 17 個 focused cases。

區塊 單獨壞掉的條件
前提 一個 Must Have 都沒有
主要流程 沒有步驟;needsReview 為 true
功能規格 缺 actor;缺 userValue;第二個 Must Have 沒有 spec;沒有 behaviors;behavior 缺 trigger、systemBehavior 或 result;第二個 behavior 缺 result;basedOnRevision 過期;needsReview 為 true
專案限制 還沒 reviewed
技術設定 mode 未設定;指定技術但沒有 items;needsReview 為 true

這裡有三個小細節。

第一,缺 actor、缺 userValue、缺 trigger、缺 systemBehavior、缺 result 都用空白字串測。

這是為了確認 .trim() 真的有被算進去。

第二,今天也補了「第二個 Must Have 沒有 spec」和「第二個 behavior 缺 result」。

因為程式不是只看第一個 Must Have,也不是只看第一個 behavior。

它用的是:

mustHave.every(...)
spec.behaviors.every(...)

所以測試也要守住「每一個 Must Have」和「每一個 behavior」。

第三,basedOnRevision 那一項則是在守規格是否仍對得上目前功能定義。

目前功能改名時,feature 的 revision 會加一。

如果 feature spec 記的 basedOnRevision 還停在舊 revision,就代表它是依舊定義寫的,不應該繼續算完成。

到這裡,兩層各自守的東西就清楚了:Day 23、Day 24 的 browser test 守「結果」,也就是按鈕有沒有鎖住;今天的 unit test 守「條件」,也就是 17 個完成條件,每一個都能單獨讓判斷不通過。


沒有順手改 needs-review 規則

Day 24 文章裡有記一件事:

目前程式的 needs-review rules,和 Day 11 的 Project_Spec_Schema_v0.1.md〈十四、失效與 Needs Review 規則〉有差異。

例如現在程式比較保守:Target User、Problem、Goal 只要有變,已填過的 tech setting 也會被標成需要重新檢查。

但那張規則表裡,Target User、Problem、Goal 對 Tech Stack 是「不影響」。

Platform 這一格兩邊一致:規則表和目前程式都認為 Platform 變更會影響 Tech Stack。

反過來,也有一些規則表說應該影響、但目前程式還沒標記的情況。

這件事值得處理。

但不該混在今天。

因為 Day 25 的目標是:

先補 isSpecificationSetupComplete() 的現有行為 coverage。

今天這條測試直接把 needsReview 設成 true。

它不經過「哪些變更會觸發 needsReview」的規則。

所以之後不管要不要對齊 Schema,只要完成條件本身不變,今天這些 case 都不用動。

如果之後是把程式改成對齊 Schema,至少 Day 24 browser test 裡期待「技術設定:需要重新檢查」的那一條斷言要跟著改。


測試結果

今天先跑 focused test:

node --test test/mvpFlow.test.js
tests 2
pass 2
fail 0

再跑完整測試:

npm test
tests 31
pass 31
fail 0

Day 24 是 30 條,今天多了這 1 條。

跟 Day 24 一樣,我的執行環境第一次跑完整測試時,browser tests 會因為 local server 不能 bind 到 127.0.0.1 失敗。

放寬本機執行權限後,同一組測試通過。


Day 26 可以接哪裡

Day 25 把 isSpecificationSetupComplete() 的條件釘住了。

下一步我想補另一道防線:

generateSpecFromState()

現在 UI 按鈕會依照 isSpecificationSetupComplete() 決定能不能按。

但真正產生 spec 的 state function 裡,也有第二道 guard:

if (!isSpecificationSetupComplete(state.draft)) {
  return {
    ok: false,
    message: "請先完成主要流程、Must Have 功能規格、專案限制與技術設定。"
  };
}

如果把這段 guard 拿掉,目前 31 條測試仍然會全過。

這代表 Day 26 有一個很清楚的小洞可以補。

UI 是第一道門。

state function 是第二道門。

即使有一天畫面按鈕狀態不小心壞了,底層也不該產生一份不完整的 Project Specification。

所以 Day 26 可以補一條 focused unit test:

setup 不完整時,generateSpecFromState() 應該拒絕產生 spec,stage 不應前進,generatedSpec 不應被填入。

這會讓 Day 23 的 browser test 和 Day 26 的 state guard test 形成上下層防線。

Day 25 完成。

明天見。


上一篇
Day 24|需求改了,填過的東西我留著,但不再算完成
下一篇
Day 26|不能只相信 disabled button
系列文
AI 寫不好,可能是我沒說清楚:30 天打造 ClarifyBuild,讓 Vibe Coding 從需求開始 共 27 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言