整合測試的程式碼覆蓋率分析支援
目錄
概覽
為程式碼覆蓋率分析構建二進位制檔案
執行經過程式碼覆蓋率插樁的二進位制檔案
處理程式碼覆蓋率資料檔案
常見問題
資源
詞彙表
從 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 標準庫的一部分的包)。
例如,這是一個包含 main 包、本地主模組包 greetings
以及從模組外部匯入的一組包(其中包括 rsc.io/quote
和 fmt
)的玩具程式(完整程式連結)。
$ 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
”命令列標誌構建並執行此程式,則配置檔案中將只包含兩個包:main
和 mydomain.com/greetings
;其他依賴包將被排除。
希望對要包含在程式碼覆蓋率中的包進行更多控制的使用者可以使用“-coverpkg
”標誌進行構建。示例
$ go build -cover -o myprogramMorePkgs.exe -coverpkg=io,mydomain.com,rsc.io/quote .
$
在上面的構建中,mydomain.com
的 main 包以及 rsc.io/quote
和 io
包被選中進行分析;由於 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
”標誌可用於選擇給定報告感興趣的特定包子集。
常見問題
- 如何為
go.mod
檔案中提到的所有匯入包請求程式碼覆蓋率插樁 - 我可以在 GOPATH/GO111MODULE=off 模式下使用
go build -cover
嗎? - 如果我的程式出現 panic,會寫入程式碼覆蓋率資料嗎?
-coverpkg=main
會選擇我的 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
標誌將其他包包含在配置檔案中。
如果我的程式出現 panic,會寫入程式碼覆蓋率資料嗎?
使用 go build -cover
構建的程式只有在程式呼叫 os.Exit()
或從 main.main
正常返回時,才會在執行結束時寫入完整的配置檔案資料。如果程式因未恢復的 panic 終止,或者程式遇到致命異常(例如分段錯誤、除以零等),則執行期間執行的語句的配置檔案資料將丟失。
-coverpkg=main
會選擇我的 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 1.2 中引入單元測試覆蓋率的部落格文章:
- 單元測試的程式碼覆蓋率分析作為 Go 1.2 版本的一部分引入;有關詳細資訊,請參閱此部落格文章。
- 文件:
cmd/go
包文件描述了與程式碼覆蓋率相關的構建和測試標誌。
- 技術細節:
詞彙表
單元測試: 與特定 Go 包關聯的 *_test.go
檔案中的測試,利用 Go 的 testing
包。
整合測試: 對給定應用程式或二進位制檔案的更全面、更重量級的測試。整合測試通常涉及構建一個程式或一組程式,然後在一系列輸入和場景下執行多次程式執行,由一個測試工具控制,該工具可能基於也可能不基於 Go 的 testing
包。