測試涵蓋率

提振精神

軟體測試是常見做法,可協助團隊持續交付高品質程式碼。測試軟體行為的不變量、偵測並防止功能或其他所需屬性發生迴歸,以及協助擴大工程程序。

以原始碼行涵蓋範圍來評估測試涵蓋範圍,有助於工程師找出測試解決方案的缺口。將測試涵蓋率做為指標,有助於提升軟體品質,並促進更安全的開發做法。持續評估測試涵蓋範圍,有助於工程師維持高品質。

測試涵蓋範圍無法保證程式碼沒有錯誤。測試應與其他工具 (例如模糊測試、靜態和動態分析等) 一併使用。

絕對測試涵蓋範圍

絕對測試涵蓋範圍是指完整測試集涵蓋的所有來源程式碼行數。Fuchsia 的持續整合 (CI) 基礎架構會產生絕對涵蓋率報表,並持續更新。涵蓋範圍報表通常最多只會延遲幾小時。

絕對涵蓋範圍資訊主頁

如需最新絕對涵蓋率報告,請參閱這篇文章。 這個資訊主頁會以樹狀結構顯示所有程式碼,這些程式碼已由執行的所有測試涵蓋,屬於來源樹狀結構的子集。您可以依目錄結構瀏覽樹狀結構,並查看目錄的涵蓋範圍總指標,或檔案的個別行涵蓋範圍資訊。

此外,Google 內部程式碼搜尋功能也提供涵蓋範圍資訊做為圖層。

涵蓋範圍資訊主頁螢幕截圖

測試涵蓋率增幅

Gerrit 程式碼審查網頁版 UI 會顯示變更的增量測試涵蓋範圍。增量涵蓋範圍會顯示特定變更的背景資訊,指出哪些修改過的程式碼行已通過測試,哪些則否。

Fuchsia 的提交佇列 (CQ) 基礎架構會收集測試涵蓋率增幅。將變更傳送至 CQ (Commit-Queue+1) 時,您可以按一下「Checks」分頁標籤,然後在三點選單下方按一下「Show Additional Results」,接著在篩選文字方塊中輸入「fuchsia-coverage」,找出負責收集增量涵蓋範圍的 tryjob,以便在 Gerrit 中顯示。這項試用作業完成後,您的修補程式集應具有絕對涵蓋範圍 (|Cov.|) 和增量涵蓋範圍 (ΔCov.)

針對影響專案的變更,持續維持高增量測試涵蓋範圍,有助於持續維持高測試涵蓋範圍。特別是防止在專案中導入未經測試的新程式碼。變更作者可以查看變更的增量涵蓋範圍資訊,確保測試涵蓋範圍足夠。程式碼審查人員可以查看變更的增量測試涵蓋範圍資訊,並要求作者填補他們認為重要的測試缺口。

Gerrit 螢幕截圖,顯示涵蓋率統計資料

Gerrit 螢幕截圖,顯示程式碼涵蓋範圍

以涵蓋範圍為導向的開發工作流程

您可以在瀏覽器或 VS Code 中查看本機編輯作業的涵蓋範圍。 您可以使用這項功能建立以涵蓋範圍為導向的開發工作流程。

準備測試環境

首先,請設定建構作業,使用涵蓋範圍變數,並納入用於示範工作流程的範例。

C++

fx set core.x64 --variant coverage --with examples/hello_world --include-clippy=false
fx build

荒漠油廠

fx set core.x64 --variant coverage-rust --with examples/hello_world
fx build

首先啟動模擬器 (即目標裝置),然後啟動更新伺服器。這個步驟會用到兩個終端機。如果您已執行目標裝置 (模擬器或實體硬體),可以略過這個步驟。

在第一個終端機中:

fx qemu -kN

接著,啟動套件伺服器,用來將更新發布至測試套件,這個程序會在背景執行。如果已執行套件伺服器,可以略過這個步驟。

在第二個終端機中:

fx serve

在瀏覽器中查看涵蓋範圍

在這個工作流程中,我們會執行測試並產生涵蓋範圍報表,以便在瀏覽器中查看。

執行測試並匯出涵蓋範圍 HTML 報表

我們會執行測試並產生 HTML 報表。

C++

fx coverage --html-output-dir $HOME/fx_coverage hello-world-cpp-unittests

荒漠油廠

fx coverage --html-output-dir $HOME/fx_coverage hello-world-rust-tests

在瀏覽器中查看涵蓋範圍摘要

使用瀏覽器開啟 $HOME/fx_coverage/index.html。您應該會看到涵蓋範圍摘要頁面。

涵蓋範圍報表螢幕截圖

按一下任一檔案,即可查看該檔案的行涵蓋率。「計數」欄會顯示測試期間的行造訪次數,至少為 1 次。「Count」沒有值表示 0,也就是該行未涵蓋。

在 VS Code 中查看涵蓋範圍

請先準備測試環境,再開始本節內容。

  1. 從 Visual Studio Marketplace 安裝 coverage-gutters 擴充功能。
  2. 將下列屬性新增至 settings.json,即可設定涵蓋範圍間距。
{
    "coverage-gutters.coverageBaseDir": ".",
    "coverage-gutters.showLineCoverage": true,
    "coverage-gutters.coverageFileNames": [ "lcov.info" ]
}

執行測試並查看涵蓋範圍

現在執行測試並匯出 LCOV 檔案,VS Code 會使用這個檔案顯示涵蓋範圍。

C++

fx coverage --lcov-output-path $FUCHSIA_DIR/lcov.info hello-world-cpp-unittests

荒漠油廠

fx coverage --lcov-output-path $FUCHSIA_DIR/lcov.info hello-world-rust-tests

在 VS Code 中查看涵蓋範圍

  1. 找出要查看涵蓋範圍的檔案。
  2. 在檔案的編輯區域上按一下滑鼠右鍵,然後選取「Coverage Gutters: Display Coverage」。
  3. 綠色代表已涵蓋的路線,紅色代表未涵蓋的路線。
  4. 您可以重新匯出 LCOV,然後重新執行步驟 2,查看更新後的涵蓋範圍 (由於某些原因,「watch」無法運作)。

顯示涵蓋率

VS Code 涵蓋率

對變更重新執行測試

最後,您可以使用這項指令監控檔案系統變更,並在每次儲存程式碼時重新執行測試。

C++

fx -i coverage --lcov-output-path $FUCHSIA_DIR/lcov.info hello-world-cpp-unittests

荒漠油廠

fx -i coverage --lcov-output-path $FUCHSIA_DIR/lcov.info hello-world-rust-tests

排除端對端 (E2E) 測試

只有單元測試和密封整合測試才算是可靠的測試涵蓋範圍來源。系統不會收集或顯示端對端測試的測試涵蓋範圍。

端對端測試是大型系統測試,會全面測試產品,不一定涵蓋原始碼中定義明確的部分。舉例來說,Fuchsia 上的 E2E 測試通常會在模擬器中啟動系統、與系統互動,並預期會出現特定行為。

原因

因為端對端測試會全面測試系統:

  • 據觀察,這些測試經常在執行期間觸發不同的程式碼路徑,導致涵蓋範圍結果不穩定。
  • 這類要求經常在涵蓋範圍建構工具上逾時,導致建構工具不穩定。端對端測試的執行速度遠慢於單元測試和小型整合測試,通常需要幾分鐘才能完成。由於涵蓋範圍的額外負荷會降低效能,因此在涵蓋範圍建構工具上執行時,速度會更慢。

方式

對於 core 等頂層 buildbot 組合,系統會提供對應的 core_no_e2e,因此收集涵蓋範圍的機器人可以使用 no_e2e 組合,避免建構及執行任何 E2E 測試。

目前沒有可靠的方法可識別樹狀結構內的所有 E2E 測試。做為 Proxy,no_e2e 組合會透過 GN 的 assert_no_deps 維護不變量,確保遞迴依附元件中沒有任何已知的端對端測試程式庫。E2E 測試程式庫清單是手動管理及維護,並假設變更頻率極低:

e2e_test_libs = [
  "//sdk/testing/sl4f/client",
  "//third_party/mobly($host_toolchain)",
  "//src/testing/end_to_end/antlion($host_toolchain)",
  "//src/testing/end_to_end/honeydew($host_toolchain)",
]

# For libraries only supported on Linux hosts, we must use host_os to determine
# whether to include them. The is_linux condition will not function as naively expected
# because it applies to the current toolchain which may not be a host toolchain
# when this file is loaded.
if (host_os == "linux") {
  e2e_test_libs += [ "//tools/emulator($host_toolchain)" ]
}

限制

目前,只有在下列情況下,系統才會收集測試涵蓋範圍:

  • 程式碼是以 C、C++ 或 Rust 編寫。
  • 程式碼會在 Fuchsia 的使用者模式下執行,或在主機上執行。目前不支援核心涵蓋範圍 (追蹤錯誤)。
  • 測試會在 qemu 上執行。目前尚不支援在硬體上進行測試。
  • 測試會以 core 產品設定的一部分執行。
  • 系統不支援端對端 (e2e) 測試。

最後一點,端對端測試會在整個系統中執行大量程式碼,但執行方式在不同執行程序之間不一致 (或「不穩定」)。如要提高程式碼的測試涵蓋範圍,建議使用單元測試和整合測試。

實驗功能

根據預設,系統只會在 core.x64 中收集增量涵蓋範圍。如要收集 core.x64core.arm64 中變更的合併涵蓋範圍,請按照下列步驟操作:

  1. 在 Gerrit 中,前往「檢查」分頁。
  2. 按下「選擇試用工作」。
  3. 新增 fuchsia-coverage-x64-arm64

在 Gerrit 中手動選擇 x64-arm64 涵蓋範圍

畫面會顯示勾號,狀態從「待處理」變成「完成」後,請重新整理 Gerrit,即可查看涵蓋範圍結果。

另請參閱: Issue 91893: Incremental coverage in Gerrit only collected for x64

即將推出的新功能

我們目前正在開發下列其他用途的支援功能:

  • 核心程式碼涵蓋率。
  • 涵蓋範圍為 core 以外的產品設定,例如 bringupworkstation_eng
  • 硬體目標的涵蓋範圍,也就是從未在 qemu 上執行的測試收集資料。

疑難排解

不支援的設定 / 語言 / 執行階段

如果程式碼沒有顯示絕對或增量涵蓋範圍資訊,請先查看限制,並確認程式碼是否應獲得涵蓋範圍支援。

如要排解問題,請檢查您是否缺少涵蓋範圍 (程式碼行應有涵蓋範圍,但顯示為未涵蓋),或完全沒有涵蓋範圍資訊 (檔案完全未顯示在涵蓋範圍報表中,或程式碼行未註解是否涵蓋)。

如果缺少涵蓋範圍,表示程式碼是透過檢測設備建構,但實際執行的測試並未涵蓋該程式碼。完全沒有涵蓋範圍資訊,可能表示您的程式碼未建構涵蓋範圍,或測試未在涵蓋範圍下執行 (詳情請見下文)。

過時的報表 / 延遲

程式碼合併後,系統會產生絕對涵蓋率報表,但可能需要幾小時才能完整編譯。資訊主頁會顯示所產生報表的提交雜湊。如果資訊主頁未顯示預期結果,請確認資料是在最近影響涵蓋範圍的變更之後產生。如果資料顯示過時,請稍後再試,並重新整理頁面。

CQ 會產生涵蓋率增量報表。請確認您查看的是傳送至 CQ 的修補程式集。您可以點選「show experimental tryjobs」來顯示名為 fuchsia-coverage 的 tryjob。如果 tryjob 仍在執行,請稍後再試,並重新整理頁面。

確認測試已執行

如果程式碼缺少您預期會看到的涵蓋範圍,請選擇應涵蓋程式碼的測試,並確保該測試已在涵蓋範圍 tryjob 中執行。

  1. 在 Gerrit 中找出 tryjob,或在 CI 資訊主頁上找出最近的 fuchsia-coverage 執行作業。
  2. 在「總覽」分頁中,找出「收集建構版本」步驟並展開,即可找到不同設定的涵蓋範圍建構版本和測試執行作業頁面連結。
  3. 每個頁面都應有「測試結果」分頁,顯示所有執行的測試。確認您預期的測試已執行,最好是已通過測試。

如果測試未如預期在任何涵蓋範圍試用作業中執行,原因可能只是測試僅在 CI/CQ 目前未涵蓋的設定中執行。另一種情況是,測試在涵蓋範圍變數中明確停用。舉例來說,參照測試的 BUILD.gn 檔案可能如下所示:

fuchsia_test_package("foo_test") {
  test_components = [ ":test" ]
  deps = [ ":foo" ]

  # TODO(https://fxbug.dev/42074368): This test is intentionally disabled on coverage.
  if (is_coverage) {
    test_specs = {
      environments = [
        {
          dimensions = emu_env.dimensions
          tags = [ "disabled" ]
        },
      ]
    }
  }
}

找出測試在涵蓋範圍中遭到停用的原因,並進行調查。

如要瞭解如何排解測試未顯示涵蓋範圍的問題,請參閱這個網頁。舉例來說,如果測試未設定在 CQ 上執行,就不會顯示涵蓋範圍。

測試只會在涵蓋範圍內失敗或不穩定

如上所述,測試在涵蓋範圍 < 0x0A>example 時,更有可能發生不穩定情況。在執行階段收集涵蓋範圍會增加額外負荷,導致效能變慢,進而影響時間安排,這通常是造成額外不穩定性的原因。

另一個原因可能是測試期間發生逾時,但一般測試執行時不會遇到這種情況。實驗結果顯示,由於收集執行階段設定檔會增加額外負荷,因此平均而言,涵蓋範圍變體中的測試會慢 2.3 倍。為此,執行涵蓋範圍建構作業時,測試執行元件會為每項測試提供較長的逾時時間。不過,測試可能仍有內部作業的專屬逾時,這可能會受到影響。

一般來說,測試不應發生逾時情形。在測試中等待非同步作業時,最好無限期等待,並讓測試執行元件的整體逾時時間到期。

最後,在涵蓋範圍變體元件中,可能會使用 fuchsia.debug.DebugData 通訊協定。這會干擾測試,因為測試會假設元件使用的功能。舉例來說:

如要立即修正,請在涵蓋範圍內停用測試 (請參閱上方的 GN 代碼片段),但這樣會導致測試無法收集涵蓋範圍資訊。最佳做法是將涵蓋範圍的隨機失敗視為其他地方的隨機失敗,主要做法是修正隨機失敗問題。

另請參閱:不穩定測試政策

Gerrit 中未顯示預期涵蓋範圍

如果某些程式碼行未顯示涵蓋範圍,但您確信這些程式碼行應涵蓋在執行的測試中,請嘗試再次收集涵蓋範圍,方法是按下「Choose Tryjobs」,找到 fuchsia-coverage 並新增。

新增 fuchsia-coverage 的 Gerrit 螢幕截圖

如果 fuchsia-coverage 完成 (變成綠色),但您看到不同的程式碼涵蓋範圍結果,則表示下列其中一項為真:

  1. 測試在不同執行階段,會以不一致的方式執行受測程式碼。這通常也會導致不穩定測試結果,而且通常是測試行為或受測程式碼的問題。
  2. 產生及收集涵蓋範圍資料的方式有問題,導致結果不一致。請回報錯誤。

測試涵蓋範圍的運作方式

Fuchsia 的程式碼涵蓋率建構、測試執行階段支援和處理工具,都使用 LLVM 來源程式碼涵蓋率。編譯器執行階段設定檔支援 Fuchsia 平台。

選取 "coverage" 建構變化版本時,系統會啟用設定檔檢測。編譯器接著會產生計數器,每個計數器都對應到程式碼控制流程中的一個分支,並發出分支項目指令,以遞增相關聯的計數器。此外,設定檔檢測工具執行階段程式庫會連結至可執行檔。

如需更多實作詳細資料,請參閱「LLVM 程式碼涵蓋率對應格式」。

請注意,插樁會導致二進位檔大小增加、記憶體用量增加,以及測試執行時間變慢。為抵銷這項影響,我們採取了下列措施:

  • 設定檔變數中的測試可享有較長的逾時時間。
  • 商家檔案變化版本中的測試會經過一些最佳化處理。
  • 目前涵蓋範圍適用於儲存空間限制較少的模擬器。
  • 如要增加涵蓋範圍,系統只會對受變更影響的來源進行插碼。

Fuchsia 上的設定檔執行階段程式庫會將設定檔資料儲存在 VMO 中,並使用 fuchsia.debug.DebugData 通訊協定發布 VMO 的控制代碼。這個通訊協定會在執行階段透過 元件架構 提供給測試,並由 Test Runner Framework 的裝置端控制器 (Test Manager) 代管。

測試領域終止後,系統會收集設定檔,以及其中託管的任何元件。接著,系統會將這些設定檔處理成單一測試摘要。這項重要最佳化措施可大幅縮減設定檔總大小。接著,最佳化設定檔會傳送至主機端測試控制器。

主機使用 covargs 工具 (該工具本身使用 llvm-profdatallvm-cov 工具),將原始設定檔轉換為摘要格式,並產生測試涵蓋範圍報告。此外,covargs 會將資料轉換為 protobuf 格式,做為與各種資訊主頁的交換格式。

發展藍圖

持續進行的工作:

  • 改善涵蓋範圍執行階段的效能和可靠性。
  • 核心支援 ZBI 測試的程式碼涵蓋率。
  • 自訂涵蓋範圍資訊主頁和快訊:為團隊建立資訊主頁。
  • 本機工作流程:在本機執行測試,並在本機產生涵蓋率報告。
  • IDE 整合:在 VS Code 中查看涵蓋範圍層。

近期作業:

  • 樹外支援:涵蓋範圍超出 Fuchsia CI/CQ。

其他資訊