iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
Vibe Coding

讓 AI Agent 維護一個 Open Source Project系列 第 7

Day 07:e2e 測試環境——AI 改 CI 設定時最容易踩的坑

  • 分享至 

  • xImage
  •  

前言:CI 綠燈,跟「這個改動真的沒問題」是兩件事

「這段 CI workflow 改一改應該沒什麼風險吧?反正跑起來還是綠燈。」

如果你維護的專案只有單元測試,這句話大概沒錯。但一旦專案裡有 e2e 測試——真的啟動一個完整的執行環境、跑一次端對端流程——CI 設定本身就不再只是「怎麼觸發測試」的問題,而是「測試環境長什麼樣」的問題。這套系統背景裡(見 Day 01)反覆出現的模式,在這裡有一個特別具體的版本:AI 改 CI 設定時,很容易只確認「工作流程本身能不能跑起來」,卻沒確認「跑起來之後,測試環境是不是還跟改動前一樣」。

今日目標

  • 理解 e2e 測試環境跟單元測試環境本質上有什麼不同
  • 看一個真實案例:一個跨平台環境限制,如何讓 e2e 測試莫名其妙壞掉
  • 看一個真實案例:一次 CI workflow 重構,如何在「看起來只是搬動步驟」時悄悄改變了測試對象
  • 建立「CI 設定改動後,要驗證的不只是能不能跑,還有跑的是不是同一件事」的習慣

案例一:一個藏在作業系統限制裡的坑

PHPUnit & Pest Test Explorer 這個專案的 e2e 測試曾經在 macOS 的 CI runner 上間歇性失敗,錯誤訊息是 listen EINVAL: invalid argument .../.vscode-test/user-data/1.12-main.sock——看起來像是某種連線層級的隨機錯誤,跟改動的程式碼完全對不上。

真正的原因記錄在 PR #423 裡:macOS 對 Unix domain socket 的路徑長度有 104 位元組的硬性限制。VS Code 啟動測試環境時,預設的 --user-data-dir 會巢狀掛在整個 checkout 路徑底下(在 CI 環境裡會變成一長串巢狀目錄),這個路徑長度加上 VS Code 自己的 IPC socket 檔名,剛好超過了那個限制,導致 VS Code 啟動時直接崩潰。修法是強制指定一個短的、固定的 --user-data-dir

這個案例值得注意的地方:這不是程式邏輯錯誤,是「測試環境的物理限制」跟「程式碼假設的路徑結構」互相撞在一起的問題。 如果只看程式碼本身,完全看不出哪裡有問題——這段程式碼在 Linux、Windows 上都跑得好好的,只有 macOS 的 socket 路徑長度限制會讓它爆炸。這正是 e2e 測試環境的本質:它不只測試程式邏輯,也把作業系統、檔案系統、網路層級的行為一起捲進來測,而這些層級的限制往往不會寫在任何一份程式規格裡。

案例二:重構 CI workflow 時,悄悄換掉了測試對象

另一個更值得警惕的案例是 PR #424。這個專案原本有兩份獨立的 CI workflow:tests.yml(跑單元測試)跟 e2e.yml(跑 e2e 測試),兩份檔案裡有大量重複的環境設定步驟(checkout、安裝 PHP、安裝 pnpm/node、安裝 composer stub)。這次重構把 e2e.yml 整個刪掉,改成把 e2e 測試步驟掛進 tests.yml 既有的 OS × PHP 版本矩陣裡的其中一個 leg(PHP 8.4 那一組),CI job 數量從 12 個降到 9 個——看起來是一次單純的「消除重複設定」的重構。

但這位貢獻者自己在 PR 描述裡誠實標注了一個容易被忽略的副作用:原本獨立的 e2e.yml 只安裝一組特定版本的 PHPUnit/Pest stub(v12/v4),而合併後的 tests.yml 的 PHP 8.4 leg 會安裝所有相容版本的 stub,而 .vscode-test.mjs 的邏輯是「每種類型挑第一個偵測到的 stub」——結果 e2e 測試實際跑的版本,從 PHPUnit v12/Pest v4 變成了 PHPUnit v9/Pest v2。

用一組對照來看這個差異:

❌ 只驗證「CI 能不能跑」:
「把 e2e.yml 併進 tests.yml,job 數量減少了,CI 還是綠燈,重構完成。」
→ 沒有意識到「合併矩陣」這個動作,
  連帶改變了測試步驟實際依賴的環境細節(這裡是套件版本)

✅ 驗證「跑的是不是同一件事」:
「把 e2e.yml 併進 tests.yml 之後,e2e 測試現在依賴的是這組矩陣
 leg 裡裝的 stub 版本,而不是原本 e2e.yml 裡明確指定的版本——
 這個改變是刻意的嗎?如果原本測試特定版本是有意為之,
 需要在合併後的設定裡明確指定版本,不能讓它變成「裝到哪個就測哪個」
 的隱性行為。」
→ 把「環境重構會不會連帶改變測試對象」當成一個
  要主動確認的問題,而不是等綠燈就當作沒事

CI 設定的重構特別容易讓人掉進「這只是把步驟搬個位置」的錯覺,但 e2e 測試的正確性,高度依賴它實際跑在什麼環境裡——搬動設定的同時,很可能也在不知不覺間搬動了測試環境的定義。

為什麼這個坑對 AI 特別危險

這兩個案例合起來看,指向同一個結構性問題:AI 判斷「這個 CI 改動安不安全」時,天然傾向根據「工作流程的語法/邏輯有沒有錯」來判斷,而不是根據「這個改動有沒有影響到測試環境的實際組成」。 前者是 AI 擅長的——YAML 語法、job 依賴關係、shell 指令,這些都是可以直接讀出來的。後者需要理解「這個環境變數、這個路徑、這個版本安裝順序,最終會讓測試跑在什麼樣的具體條件下」,這件事往往要靠實際執行、觀察行為,或者像 PR #424 那樣,靠對專案歷史的熟悉才會意識到「原本這裡是刻意鎖版本的」。

這也呼應了 Day 05 講過的「隱性慣例落差」——CI 設定裡藏著大量沒有寫在任何文件裡的環境假設,AI(或任何第一次接觸這個專案的人)沒有理由天生就知道「這個矩陣的某個 leg 承擔了額外的職責」。

今日重點回顧

  • e2e 測試環境把作業系統、檔案系統、網路層級的行為一起捲進來測,這些層級的限制不會寫在程式規格裡(案例:macOS socket 路徑長度限制)
  • 重構 CI workflow 時,「消除重複設定」這個動作本身可能悄悄改變測試環境的實際組成(案例:合併矩陣後 e2e 測試跑的套件版本變了)
  • AI 判斷 CI 改動安不安全時,天然傾向看語法/邏輯對不對,而不是環境組成有沒有被連帶影響——這正是 CI 設定重構最容易被輕描淡寫放過的地方
  • CI 設定改動後要驗證的不只是「能不能跑」,還有「跑的是不是同一件事」

今日思考題

如果你的專案也有 e2e 測試環境,回想一下:CI 設定裡有沒有哪個看似單純的環境變數、路徑、或版本安裝順序,其實承擔著某個沒寫在任何文件裡的隱性職責?如果有人(或 AI)重構那段設定,你有把握這個隱性職責會被保留下來嗎?

明日預告

明天要看一次真實發生過的 CI workflow 重構全過程——從「發現重複設定」到「合併矩陣」再到「意識到副作用」,這個過程裡每一步的判斷是怎麼做的。


上一篇
Day 06:案例——AI review 一個外部貢獻的 PR,抓到什麼、漏掉什麼
下一篇
Day 07:e2e 測試環境——AI 改 CI 設定時最容易踩的坑
系列文
讓 AI Agent 維護一個 Open Source Project8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言