Go Wiki:測試失敗

如果您注意到 Go 專案中的測試失敗,應該怎麼做?

測試目標

為 Go 包編寫(和執行)測試的目標是瞭解該包及其依賴項的行為。

Go 包的測試失敗可能會提供有關以下資訊:

  • 包或其依賴項中的實現缺陷,
  • 對包 API 的錯誤假設,
  • 測試本身的錯誤(例如,有關時序的無效假設),
  • 出乎意料的高資源需求(例如,記憶體或 CPU 時間),或
  • 底層平臺中的錯誤或測試基礎設施中的缺陷(可能需要升級或規避)。

在某些情況下,測試失敗的原因可能不清楚:它可能由上述條件中的*一個以上*引起。 就像重複一項科學實驗一樣,讓測試多次失敗有時可以從特定的失敗模式中提供更多資訊。

但是,如果測試失敗但沒有提供任何新資訊,那麼該測試就沒有實現其目的。

查詢測試失敗

測試失敗通常從以下途徑注意到:

  • Go 構建儀表板,尤其是在構建器分類期間;
  • 待定更改上的 TryBot 或 SlowBot 失敗;
  • 在特定包或包上執行 go test,無論是處理 Go 專案儲存庫中的工作,還是作為使用者自己模組中的 (例如) go test all 的一部分;
  • 或在從原始碼安裝或測試貢獻的更改時執行 all.bashall.bat

對測試失敗進行分類

一旦注意到失敗,我們就需要對其進行*分類*。 分類的目標是確定:

  1. 失敗提供的資訊是新的嗎?
  2. 誰最適合分析來自失敗的新資訊?

識別新資訊

首先搜尋*開放式問題*,查詢失敗的關鍵詳細資訊,例如失敗測試的名稱和/或錯誤文字的其他獨特片段(例如,錯誤程式碼)。

如果您找到現有問題,請首先檢查問題討論,看看是否已修復該失敗,並且您的失敗資訊是否提供了相關的​​新資訊。 如果是這樣,請*在問題上發表評論*並附上詳細資訊:

  • 描述您正在測試的 Go 版本 (go version)
  • 如何以及在哪裡執行測試,例如:
    • go env 輸出
    • 您的機器和作業系統配置
    • 您的網路配置和狀態
  • 您是否能夠重現失敗以及重現的頻率。

理想情況下,附加或連結到完整的測試日誌(可能放在 <details> 塊中)。

如果您找不到現有問題,請提交一個新問題。

提交問題

貼上足夠的測試日誌,以便將來的報告者能夠搜尋到該問題,包括測試的名稱及其日誌輸出中的任何獨特部分。(如果測試日誌很長 — 例如,如果它包含大型 goroutine 轉儲 — 考慮釋出較短的摘錄和/或將完整的失敗訊息包含在 <details> 塊中。)

您可以使用 fetchlogsgreplogs 工具來搜尋構建儀表板中類似的失敗。

# download recent logs
fetchlogs -n 1024 -repo all
# search logs for some regexp describing the failure message
greplogs -l -e $FAILURE_REGEXP

如果失敗似乎特定於某個包,請查閱 https://dev.golang.org/owners 查詢該包的維護者,並在問題中提及他們。(如果包未列出所有者,請檢查該包在 https://cs.opensource.google/go 上的近期歷史記錄,以及/或升級給能幫助識別相關所有者的人 — 並考慮使用您學到的知識更新所有者表!)

如果失敗似乎特定於 GOOSGOARCH,請用相應的 GOOS 和/或 GOARCH 標籤標記問題,並在問題中提及 @golang/port-maintainers 的相關子團隊。

如果失敗似乎影響了至少一個*一流埠*,請將問題新增到當前釋出里程碑,並標記為 release-blocker。否則,將問題新增到 Backlog 里程碑。

如果失敗似乎特定於某個構建器(例如,網路連線問題或需要系統更新的平臺錯誤),請查閱 x/build/dashboard/builders.go 查詢該構建器的維護者,並在問題中提及他們。(對於沒有明確列出維護者的構建器,請提及 @golang/release 團隊。)

處理測試失敗

一旦為測試失敗提交了問題,相關的包、埠和/或構建器維護者應檢查從測試失敗中獲得的​​資訊,並透過以下一項或多項操作來決定如何*處理*它:

  • 撤銷對被認為引入問題的程式碼或測試基礎設施的更改,
  • 修復(或應用變通方法)失敗的根本原因,
  • 收集更多資訊,透過訂閱問題更新和/或執行更多測試,
  • 報告底層依賴項、平臺或測試基礎設施中的缺陷,以及/或
  • 降低失敗的優先順序,透過在受影響的平臺上跳過失敗(或將這些平臺標記為已損壞),然後將問題移至未來的或 Backlog 里程碑,以及/或刪除 release-blocker 標籤。

當維護者決定降低測試失敗的優先順序時,他們會確定*該測試的其他失敗將不會提供有用的新資訊*。 此時,測試不再履行其目的,維護者應抑制失敗 — 通常透過新增對 testenv.SkipFlakyt.Skipf 的呼叫。

跳過測試失敗

當我們新增對 testenv.SkipFlaky 的呼叫時,我們的目標是消除不提供新資訊的失敗模式,同時儘可能保留測試的價值。

  • 如果觀察到的失敗只是測試的幾種可能失敗模式之一,則僅為該失敗模式跳過測試。

    • 例如,如果錯誤始終是特定的,如 syscall.ECONNRESET,請使用 errors.Is 檢查該特定錯誤。
  • 如果認為失敗會影響特定 GOOS 和/或 GOARCH 的所有版本,或者無法確定受影響的版本,請根據 runtime.GOOS 和/或 runtime.GOARCH 進行檢查,並僅跳過受影響的平臺。

  • 如果失敗是由於*特定版本*的平臺上的錯誤,請根據 testenv.BuilderGO_BUILDER_NAME 環境變數跳過測試。(如果測試對外部 Go 使用者失敗,他們可以選擇升級到不受影響的平臺版本 — 他們很可能應該看到測試失敗以瞭解該錯誤的存在!)

    • 還應考慮新增另一個環境變數,使用者和貢獻者可以設定該變數來確認錯誤並抑制失敗。

將構建器或埠標記為已損壞

平臺錯誤或核心包(如 osnetruntime)中的錯誤可能會影響如此多的測試,以至於無法跳過失敗,或者可能會表現為編譯或連結時失敗。 如果發生此類錯誤,選項將更加有限:如果我們無法撤銷更改或修復或規避根本原因,並且不需要收集更多資訊,我們只能透過將*整個構建器或平臺*標記為已損壞來降低失敗的優先順序。

要將構建器標記為已損壞,請在其 x/build/dashboard/builders.go 配置中進行編輯,在 KnownIssue 欄位中新增一個問題;請注意,已知問題構建器通常會在儀表板分類期間被跳過。

一流埠的損壞構建器應將其已知問題標記為 release-blocker,等待決定是修復構建器還是放棄對受影響平臺版本的支援。

如果次要埠的所有構建器都已損壞,則該埠本身可能被視為已損壞。 討論 #53060 旨在解決如何處理已損壞的次要埠的問題。


此內容是 Go Wiki 的一部分。