整合測試的涵蓋率剖析支援

目錄

概觀
建置用於涵蓋率剖析的二進位檔
執行涵蓋率工具化的二進位檔
使用涵蓋率資料檔案
常見問題
資源
詞彙表

從 Go 1.20 開始,Go 支援從應用程式和整合測試中收集涵蓋範圍設定檔,這是針對 Go 程式較大型且複雜的測試。

概觀

Go 提供容易使用的支援,透過「go test -coverprofile=... <pkg_target>」指令在套件單元測試層級收集涵蓋範圍設定檔。從 Go 1.20 開始,使用者現在可以為較大型的 整合測試 收集涵蓋範圍設定檔:執行給定應用程式二進位檔多次的較重型、複雜測試。

對於單元測試,收集涵蓋範圍設定檔和產生報告需要兩個步驟:執行 go test -coverprofile=...,接著呼叫 go tool cover {-func,-html} 來產生報告。

對於整合測試,需要三個步驟:建置步驟、執行步驟(可能包含從建置步驟呼叫二進位檔多次),最後是 報告 步驟,如下所述。

建置用於涵蓋率剖析的二進位檔

要建置用於收集涵蓋範圍設定檔的應用程式,請在應用程式二進位檔目標上呼叫 go build 時傳遞 -cover 旗標。請參閱 下方 的區段,取得 go build -cover 呼叫範例。然後可以使用環境變數設定來執行產生二進位檔,以擷取涵蓋範圍設定檔(請參閱 執行 的下一個區段)。

如何選取套件進行組態

在給定的「go build -cover」呼叫期間,Go 指令會選取主模組中的套件進行涵蓋範圍設定檔;其他提供給建置的套件(go.mod 中列出的相依性,或屬於 Go 標準函式庫的套件)預設不會包含在內。

例如,這裡有一個範例程式,包含一個主套件、一個本機主模組套件 greetings 和一組從模組外部匯入的套件,包括(在其他套件中)rsc.io/quotefmt連結至完整程式)。

$ cat go.mod
module mydomain.com

go 1.20

require rsc.io/quote v1.5.2

require (
    golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
    rsc.io/sampler v1.3.0 // indirect
)

$ cat myprogram.go
package main

import (
    "fmt"
    "mydomain.com/greetings"
    "rsc.io/quote"
)

func main() {
    fmt.Printf("I say %q and %q\n", quote.Hello(), greetings.Goodbye())
}
$ cat greetings/greetings.go
package greetings

func Goodbye() string {
    return "see ya"
}
$ go build -cover -o myprogram.exe .
$

如果您使用「-cover」命令列旗標建置這個程式並執行它,設定檔中將會包含兩個套件:mainmydomain.com/greetings;其他相依套件會被排除在外。

想要更進一步控制包含在涵蓋範圍中的套件的使用者,可以使用「-coverpkg」旗標進行建置。範例

$ go build -cover -o myprogramMorePkgs.exe -coverpkg=io,mydomain.com,rsc.io/quote .
$

在上述建置中,來自 mydomain.com 的主要套件以及 rsc.io/quoteio 套件已選取進行分析;由於 mydomain.com/greetings 沒有特別列出,因此會從分析中排除,即使它存在於主要模組中。

執行涵蓋率工具化的二進位檔

使用「-cover」建置的二進位檔會在其執行結束時,將分析資料檔案寫入透過環境變數 GOCOVERDIR 指定的目錄中。範例

$ go build -cover -o myprogram.exe myprogram.go
$ mkdir somedata
$ GOCOVERDIR=somedata ./myprogram.exe
I say "Hello, world." and "see ya"
$ ls somedata
covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
covmeta.c6de772f99010ef5925877a7b05db4cc
$

請注意寫入目錄 somedata 的兩個檔案:這些(二進位)檔案包含分析結果。請參閱 報告 中的下一章節,以進一步瞭解如何從這些資料檔案產生人類可讀的結果。

如果未設定 GOCOVERDIR 環境變數,經過分析工具處理的二進位檔仍會正確執行,但會發出警告。範例

$ ./myprogram.exe
warning: GOCOVERDIR not set, no coverage data emitted
I say "Hello, world." and "see ya"
$

涉及多重執行的測試

整合測試在許多情況下可能涉及多重程式執行;當程式使用「-cover」建置時,每次執行都會產生一個新的資料檔案。範例

$ mkdir somedata2
$ GOCOVERDIR=somedata2 ./myprogram.exe          // first run
I say "Hello, world." and "see ya"
$ GOCOVERDIR=somedata2 ./myprogram.exe -flag    // second run
I say "Hello, world." and "see ya"
$ ls somedata2
covcounters.890814fca98ac3a4d41b9bd2a7ec9f7f.2456041.1670259309405583534
covcounters.890814fca98ac3a4d41b9bd2a7ec9f7f.2456047.1670259309410891043
covmeta.890814fca98ac3a4d41b9bd2a7ec9f7f
$

分析資料輸出檔案有兩種形式:元資料檔案(包含從執行到執行不變的項目,例如原始檔名稱和函式名稱),以及計數器資料檔案(記錄執行的程式部分)。

在上述範例中,第一次執行產生兩個檔案(計數器和元資料),而第二次執行只產生一個計數器資料檔案:由於元資料不會隨著執行而改變,因此只需要寫入一次。

使用涵蓋率資料檔案

Go 1.20 引入了新的工具「covdata」,可用於讀取和處理來自 GOCOVERDIR 目錄的分析資料檔案。

Go 的 covdata 工具以多種模式執行。covdata 工具呼叫的一般形式如下

$ go tool covdata <mode> -i=<dir1,dir2,...> ...flags...

其中「-i」旗標提供要讀取的目錄清單,每個目錄都是從經過分析工具處理的二進位檔執行(透過 GOCOVERDIR)衍生的。

建立涵蓋範圍設定檔報告

本節討論如何使用「go tool covdata」從涵蓋範圍資料檔產生人類可讀的報告。

報告涵蓋的百分比陳述

若要為每個已編入工具的套件報告「涵蓋的百分比陳述」指標,請使用指令「go tool covdata percent -i=<directory>」。使用上方 執行 區段的範例

$ ls somedata
covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
covmeta.c6de772f99010ef5925877a7b05db4cc
$ go tool covdata percent -i=somedata
    main    coverage: 100.0% of statements
    mydomain.com/greetings  coverage: 100.0% of statements
$

此處的「涵蓋的陳述」百分比直接對應於 go test -cover 所報告的百分比。

轉換為舊版文字格式

你可以使用 covdata textfmt 選擇器將二進位涵蓋範圍資料檔轉換成「go test -coverprofile=<outfile>」所產生的舊版文字格式。然後可以使用「go tool cover -func」或「go tool cover -html」使用產生的文字檔建立其他報告。範例

$ ls somedata
covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
covmeta.c6de772f99010ef5925877a7b05db4cc
$ go tool covdata textfmt -i=somedata -o profile.txt
$ cat profile.txt
mode: set
mydomain.com/myprogram.go:10.13,12.2 1 1
mydomain.com/greetings/greetings.go:3.23,5.2 1 1
$ go tool cover -func=profile.txt
mydomain.com/greetings/greetings.go:3:  Goodbye     100.0%
mydomain.com/myprogram.go:10:       main        100.0%
total:                  (statements)    100.0%
$

合併

go tool covdata」的 merge 子指令可用於合併來自多個資料目錄的設定檔。

例如,考慮一個在 macOS 和 Windows 上執行的程式。此程式的作者可能想要將在每個作業系統上個別執行的涵蓋範圍設定檔合併成單一設定檔主體,以便產生跨平台涵蓋範圍摘要。例如

$ ls windows_datadir
covcounters.f3833f80c91d8229544b25a855285890.1025623.1667481441036838252
covcounters.f3833f80c91d8229544b25a855285890.1025628.1667481441042785007
covmeta.f3833f80c91d8229544b25a855285890
$ ls macos_datadir
covcounters.b245ad845b5068d116a4e25033b429fb.1025358.1667481440551734165
covcounters.b245ad845b5068d116a4e25033b429fb.1025364.1667481440557770197
covmeta.b245ad845b5068d116a4e25033b429fb
$ ls macos_datadir
$ mkdir merged
$ go tool covdata merge -i=windows_datadir,macos_datadir -o merged
$

上述的合併作業將合併指定輸入目錄中的資料,並將一組新的合併資料檔寫入「merged」目錄。

套件選擇

大多數「go tool covdata」指令支援「-pkg」旗標,以在作業中執行套件選擇;「-pkg」的引數採用與 Go 指令的「-coverpkg」旗標相同的形式。範例


$ ls somedata
covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
covmeta.c6de772f99010ef5925877a7b05db4cc
$ go tool covdata percent -i=somedata -pkg=mydomain.com/greetings
    mydomain.com/greetings  coverage: 100.0% of statements
$ go tool covdata percent -i=somedata -pkg=nonexistentpackage
$

-pkg」旗標可用於選取給定報告中感興趣的特定套件子集。

常見問題

  1. 我如何要求對 go.mod 檔案中提到的所有已匯入套件進行涵蓋範圍工具化
  2. 我可以在 GOPATH/GO111MODULE=off 模式中使用 go build -cover 嗎?
  3. 如果我的程式發生恐慌,會寫入涵蓋範圍資料嗎?
  4. -coverpkg=main 會選取我的主套件進行剖析嗎?

我如何要求對 go.mod 檔案中提到的所有已匯入套件進行涵蓋範圍工具化

預設情況下,go build -cover 會對所有主模組套件進行涵蓋範圍工具化,但不會對主模組外部的匯入進行工具化(例如標準函式庫套件或 go.mod 中列出的匯入)。要求對所有非標準函式庫相依項進行工具化的其中一種方式,是將 go list 的輸出提供給 -coverpkg。以下是範例,再次使用上面引用的 範例程式

$ go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' -deps . | paste -sd "," > pkgs.txt
$ go build -o myprogram.exe -coverpkg=`cat pkgs.txt` .
$ mkdir somedata
$ GOCOVERDIR=somedata ./myprogram.exe
$ go tool covdata percent -i=somedata
    golang.org/x/text/internal/tag  coverage: 78.4% of statements
    golang.org/x/text/language  coverage: 35.5% of statements
    mydomain.com    coverage: 100.0% of statements
    mydomain.com/greetings  coverage: 100.0% of statements
    rsc.io/quote    coverage: 25.0% of statements
    rsc.io/sampler  coverage: 86.7% of statements
$

我可以在 GO111MODULE=off 模式中使用 go build -cover 嗎?

是的,go build -cover 確實可搭配 GO111MODULE=off 使用。在 GO111MODULE=off 模式中建置程式時,只有在命令列中特別指定為目標的套件會進行工具化以進行剖析。使用 -coverpkg 旗標將其他套件納入剖析。

如果我的程式發生恐慌,會寫入涵蓋範圍資料嗎?

使用 go build -cover 建置的程式,只有在程式呼叫 os.Exit() 或從 main.main 正常傳回時,才會在執行結束時寫出完整的剖析資料。如果程式在未復原的恐慌中終止,或如果程式遇到致命例外(例如區段違規、除以零等),則在執行期間執行的陳述式的剖析資料將會遺失。

-coverpkg=main 會選取我的主套件進行剖析嗎?

-coverpkg 旗標接受匯入路徑清單,而非套件名稱清單。如果你想針對你的 main 套件選擇涵蓋範圍儀器,請透過匯入路徑而非名稱來識別它。範例(使用 這個範例程式

$ go list -m
mydomain.com
$ go build -coverpkg=main -o oops.exe .
warning: no packages being built depend on matches for pattern main
$ go build -coverpkg=mydomain.com -o myprogram.exe .
$ mkdir somedata
$ GOCOVERDIR=somedata ./myprogram.exe
I say "Hello, world." and "see ya"
$ go tool covdata percent -i=somedata
    mydomain.com    coverage: 100.0% of statements
$

資源

詞彙表

單元測試: 在與特定 Go 套件相關的 *_test.go 檔案中的測試,使用 Go 的 testing 套件。

整合測試: 針對特定應用程式或二進位檔案進行更全面、更重量級的測試。整合測試通常涉及建置程式或一組程式,然後使用多個輸入和場景執行程式的一系列執行,在測試架構的控制下,該架構可能基於 Go 的 testing 套件,也可能不基於該套件。