計測のためにパッケージが選択される方法
特定の「go build -cover
」呼び出し中に、Goコマンドはカバレッジプロファイリングのためにメインモジュール内のパッケージを選択します。他のパッケージ(go.modにリストされている依存関係やGo標準ライブラリの一部であるパッケージ)は、デフォルトでは含まれません。
例えば、メインパッケージ、ローカルメインモジュールパッケージ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
」コマンドラインフラグでビルドして実行すると、プロファイルには正確に2つのパッケージが含まれます:main
とmydomain.com/greetings
;他の依存パッケージは除外されます。
カバレッジに含まれるパッケージをより制御したいユーザーは、「-coverpkg
」フラグでビルドできます。例:
$ go build -cover -o myprogramMorePkgs.exe -coverpkg=io,mydomain.com,rsc.io/quote .
$
上記のビルドでは、mydomain.com
からのメインパッケージと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
に書き込まれた2つのファイルに注意してください:これらの(バイナリ)ファイルにはカバレッジ結果が含まれています。これらのデータファイルから人間が読み取れる結果を生成する方法については、次のセクションの報告を参照してください。
``````bash
$ ./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
$
カバレッジデータ出力ファイルには2つの種類があります:メタデータファイル(実行ごとに不変の項目を含む、例えばソースファイル名や関数名)とカウンタデータファイル(実行されたプログラムの部分を記録します)。
上記の例では、最初の実行で2つのファイル(カウンタとメタ)が生成されましたが、2回目の実行ではカウンタデータファイルのみが生成されました:メタデータは実行ごとに変わらないため、一度だけ書き込む必要があります。
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
によって報告されたものと直接対応しています。
レガシーテキスト形式への変換
バイナリカバレッジデータファイルを「go test -coverprofile=<outfile>
」によって生成されたレガシーテキスト形式に変換するには、covdata textfmt
セレクタを使用できます。生成されたテキストファイルは、「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
にリストされているインポート)は計測しません。すべての非標準ライブラリ依存関係に対して計測をリクエストする方法の1つは、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は私のメインパッケージをプロファイリングのために選択しますか?
``````bash
$ 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
パッケージに基づくかどうかにかかわらずテストハーネスの制御下で実行されます。