bughunt 是做什麼的?
單元測試和多數 UI 測試只檢查作者想到的程式路徑,而且常常透過繞過真實點擊和按鍵的測試鉤子來進行。但人們並非這樣使用應用程式。他們會點擊鉤子沒覆蓋到的地方,會在做完每件事後按下復原,會在狹窄的視窗中工作,會在半途中斷網路,還會打開同事傳來的那個奇怪檔案。他們遇到的大多數錯誤本來就存在,只是沒有人去尋找。
這個技能會去尋找。它用真實的輸入來驅動真實的應用程式,一次專注一個區域,並將每個確認的錯誤記錄兩次:一次是作為留在儲存庫中的失敗測試,這樣錯誤就不能在無人察覺的情況下再次出現;另一次是作為儲存庫錯誤清單中的條目,以便有人修復它。一次探索不修復產品程式碼。它負責發現、證明和記錄。
模式
- Hunt (預設模式):選擇一個區域,探索它,記錄發現,並更新輪換紀錄。每次執行只處理一個區域,這能確保探索的深度足以發現真正的錯誤。
- Set up:當儲存庫沒有辦法端到端驅動應用程式,或者缺少
references/boundaries.md中定義的邊界時使用。建立一個能夠在每個平台上執行一項功能的最小逐步操作通道 (references/walkthroughs.md),然後進行探索。 - Sweep:執行所有現有的逐步操作,並報告自上次執行以來有哪些是新發現、哪些已改變、以及哪些已被修復。掃描能找出回歸錯誤,但不會發現新型態的錯誤;請與探索搭配使用。
- Rules:將
references/invariants.md中的其中一條規則加入到操作通道中,使該規則在每個逐步操作的每個步驟上運作。一條單一的規則(例如「復原會恢復到完全相同的先前狀態」)就能在跨功能的範圍內浮現數十個沒人會想到要去編寫腳本的錯誤。
1. 先了解基本規則
閱讀儲存庫的說明檔案(CLAUDE.md、AGENTS.md、CONTRIBUTING、任何規則或交接備忘錄)、執行應用程式的 README,以及現有的端到端測試。找出:
- 如何啟動應用程式擁有的每個平台:開發伺服器、桌面建置版、行動模擬器。一個平台是指在一個外觀(淺色、深色、高對比)和一個尺寸(寬、窄、手機)下的一種宿主(網頁、桌面、行動裝置)。
- 錯誤在哪裡追蹤(錯誤檔案、待辦事項清單、問題追蹤器)以及條目使用的格式。請使用該格式撰寫。
- 測試絕對不能碰觸什麼:真實帳號、真實使用者檔案、正式環境資料、真實電子郵件、付款、使用者的剪貼簿、印表機和瀏覽器、已安裝的應用程式副本。閱讀
references/boundaries.md,並在驅動任何東西之前先設定好所有適用的邊界。這是探索過程中可能造成真正損害的部分,所以要先做。 - 儲存庫是否禁止任何其他事項(例如推送、網路存取、付費服務、啟動代理程式)。這些規則的優先級高於本技能。
只有在答案會改變你可以觸碰的內容時才提問。否則,自行選擇,並在探索報告中寫下你的假設。
2. 選擇區域並列出其功能
使用被指定的區域。否則,讀取 bughunt/areas.md(初次執行時從 templates/areas.md 建立),並按照以下順序選擇:從未被探索過的區域,然後是自上次探索以來有變更的區域(在其路徑上執行 git log),最後是陳舊度最高的區域。一個區域是指使用者會一起使用的一組功能:文件編輯器、檔案瀏覽器、登入與帳號、設定、分享、付款。
從儲存庫中的任何資料(功能註冊表、選單和命令列、路由、說明頁面、程式碼的進入點)列出該區域的功能。每個功能都必須在每個平台上至少執行一次。
3. 探索
對於每個功能,首先以真實使用者會做的方式,在合理的合成檔案上從頭到尾操作一次。然後,按照 references/checklist.md 進行操作。這是一份反覆導致應用程式崩潰的敵意使用者行為清單:每一步都進行復原、僅用鍵盤、窄視窗、深色模式、中途離線、最大且最損毀的檔案、透過另一種格式進行往返、在同一個雙分頁中進行相同操作、故意製造失敗。
使用真實的輸入事件(點擊、按鍵、拖曳、打字)以人類的速度驅動應用程式。腳本執行速度比人類快,因此在點擊後稍等片刻,再進行下一個動作;在兩個你預期要分別復原的變更之間,留下半秒鐘的間隔。否則,你會把時序問題當成錯誤來記錄。
注意每一步的:
- 錯誤的結果,或是一個正確但無法持久保留的結果(重新載入、儲存、復原或切換分頁後消失)
- 遺失的工作:編輯內容、設定、選取範圍、捲動位置
- 復原操作還原太多、太少,或完全沒有效果
- 一個沒有作用的命令、只能從其中一個進入點執行、或在無法執行時沒有被停用
- 原始錯誤文字:堆疊追蹤、錯誤代碼、內部路徑
- 主控台錯誤、當機、空白視窗、無回應
- 文字太淡、被裁切、重疊、或中間斷字(
references/invariants.md中的螢幕擷取檢查大多能自動捕捉這類問題) - 同一個步驟在不同平台上有不同行為
看到每個候選錯誤時就記錄下來,包括平台、步驟和你的預期結果。然後繼續進行;在功能探索結束時再進行確認。
4. 在提交前先確認
探索的可信度取決於其發現是否真實。針對每個候選錯誤:
- 從乾淨狀態下重現兩次,以人類的速度,透過手動或最小腳本進行。如果無法重現,則捨棄它,或者以「未驗證:」的形式記錄你看到的內容和位置。
- 排除測試本身的問題。 時序問題(見上述說明)、選擇器匹配到錯誤的元素、測試本身的樁程式碼、未聚焦的視窗、游標停留在具有懸浮狀態的元素上。一個會隨著游標位置而出現或消失的發現是真實的,但需要在測試中為游標指定一個固定的位置。
- 在代價不大的情況下找出原因。 在可能的位置閱讀程式碼,並指出檔案和函數的名稱。不要花太多時間在這裡;修復者會進行後續處理。
- 檢查錯誤追蹤器。 如果已有條目涵蓋此問題,則將新的平台或細節添加到該條目中,而不是建立新條目。
- 按根本原因分組。 多個症狀通常共享一個原因(例如,一個缺失的按鍵繫結可能使同一宿主上的五個編輯器的復原功能都失效)。請說明這一點,以便一次修復就能解決問題。
5. 記錄每個確認的錯誤
- 先建立一個失敗的測試。 在該功能的逐步操作中(或一個新的逐步操作中)添加一個步驟,其預期結果應說明應該發生什麼。執行它並確認它失敗了,而且失敗的原因是這個錯誤,而不是其他原因。錯誤修復後,這個測試就會通過。永遠不要為了讓測試通過而削弱現有的預期結果或螢幕擷取檢查。如果一個檢查是錯誤的,請在報告中說明原因,並將其留給真人處理。
- 然後是錯誤條目,放在儲存庫錯誤清單的末尾,使用其格式,並參考
templates/bug-entry.md:使用使用者的話描述症狀、實際發生的情況與應該發生的情況、測量到的數據、程式碼中的位置、哪個測試保護著它、以及在哪些平台上出現。 - 探索過程中不修改產品程式碼,除非被要求進行修復。邊進行邊修復會隱藏發現,並混雜兩種不同類型的審查。
- 如果儲存庫的規則允許,則提交新的測試和錯誤條目,並按檔案名稱暫存。除非被告知,否則不要推送。
6. 報告與輪換
根據 templates/hunt-report.md 撰寫探索報告:區域、平台、每個發現及其測試和條目、你捨棄的候選錯誤及其原因、你無法測試的內容,以及按原因分組的建議修復方式。更新 bughunt/areas.md 中該區域的資料行(日期、提交、發現)。
最後,用白話告訴使用者:確認了多少個錯誤、最嚴重的三個錯誤是什麼、修復分組是什麼,以及輪換機制會選擇的下一個區域是什麼。
持續尋找
一次完成的探索會留下測試,用來捕捉相同錯誤的再次出現。新的錯誤需要新的尋找:
- 按照輪換再次探索。在一個區域發生重大變更後,重新探索該區域。
- 將一個反覆在新地方出現的錯誤轉化為規則(
references/invariants.md),以便每個步驟都檢查它。 - 使用者回報的每個錯誤,在修復之前都應該先變成一個逐步操作的步驟。
- 在每次發行前執行整個操作通道,如果儲存庫允許排程器,則每晚執行。只報告新的和改變的失敗,這樣一個已知的錯誤就不會掩蓋一個新的錯誤。
當工作量很大時
如果你可以跨模型或會話拆分工作,請使用你最強的模型進行探索,並在一個新的會話中使用不同的模型進行確認。第二輪會從乾淨狀態重新執行每個失敗的測試,並重新閱讀每個條目。這可以捕捉到單一輪次容易保留的、過於自信的假陽性錯誤。