計測のためにパッケージが選択される方法

特定の「go build -cover」呼び出し中に、Goコマンドはカバレッジプロファイリングのためにメインモジュール内のパッケージを選択します。他のパッケージ(go.modにリストされている依存関係やGo標準ライブラリの一部であるパッケージ)は、デフォルトでは含まれません。

例えば、メインパッケージ、ローカルメインモジュールパッケージgreetings、および外部からインポートされたパッケージ(rsc.io/quotefmtを含む)を含むおもちゃプログラムがあります(完全なプログラムへのリンク)。

  1. $ cat go.mod
  2. module mydomain.com
  3. go 1.20
  4. require rsc.io/quote v1.5.2
  5. require (
  6. golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
  7. rsc.io/sampler v1.3.0 // indirect
  8. )
  9. $ cat myprogram.go
  10. package main
  11. import (
  12. "fmt"
  13. "mydomain.com/greetings"
  14. "rsc.io/quote"
  15. )
  16. func main() {
  17. fmt.Printf("I say %q and %q\n", quote.Hello(), greetings.Goodbye())
  18. }
  19. $ cat greetings/greetings.go
  20. package greetings
  21. func Goodbye() string {
  22. return "see ya"
  23. }
  24. $ go build -cover -o myprogram.exe .
  25. $

このプログラムを「-cover」コマンドラインフラグでビルドして実行すると、プロファイルには正確に2つのパッケージが含まれます:mainmydomain.com/greetings;他の依存パッケージは除外されます。

カバレッジに含まれるパッケージをより制御したいユーザーは、「-coverpkg」フラグでビルドできます。例:

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

上記のビルドでは、mydomain.comからのメインパッケージとrsc.io/quoteおよびioパッケージがプロファイリングのために選択されます;mydomain.com/greetingsが特にリストされていないため、メインモジュールに存在していてもプロファイルから除外されます。

-cover」でビルドされたバイナリは、実行の最後に環境変数GOCOVERDIRで指定されたディレクトリにプロファイルデータファイルを書き出します。例:

  1. $ go build -cover -o myprogram.exe myprogram.go
  2. $ mkdir somedata
  3. $ GOCOVERDIR=somedata ./myprogram.exe
  4. I say "Hello, world." and "see ya"
  5. $ ls somedata
  6. covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
  7. covmeta.c6de772f99010ef5925877a7b05db4cc
  8. $

ディレクトリsomedataに書き込まれた2つのファイルに注意してください:これらの(バイナリ)ファイルにはカバレッジ結果が含まれています。これらのデータファイルから人間が読み取れる結果を生成する方法については、次のセクションの報告を参照してください。

  1. ``````bash
  2. $ ./myprogram.exe
  3. warning: GOCOVERDIR not set, no coverage data emitted
  4. I say "Hello, world." and "see ya"
  5. $
  6. `

複数回の実行を含むテスト

統合テストは多くの場合、複数のプログラム実行を含むことがあります。「-cover」でビルドされたプログラムでは、各実行が新しいデータファイルを生成します。例

  1. $ mkdir somedata2
  2. $ GOCOVERDIR=somedata2 ./myprogram.exe // first run
  3. I say "Hello, world." and "see ya"
  4. $ GOCOVERDIR=somedata2 ./myprogram.exe -flag // second run
  5. I say "Hello, world." and "see ya"
  6. $ ls somedata2
  7. covcounters.890814fca98ac3a4d41b9bd2a7ec9f7f.2456041.1670259309405583534
  8. covcounters.890814fca98ac3a4d41b9bd2a7ec9f7f.2456047.1670259309410891043
  9. covmeta.890814fca98ac3a4d41b9bd2a7ec9f7f
  10. $

カバレッジデータ出力ファイルには2つの種類があります:メタデータファイル(実行ごとに不変の項目を含む、例えばソースファイル名や関数名)とカウンタデータファイル(実行されたプログラムの部分を記録します)。

上記の例では、最初の実行で2つのファイル(カウンタとメタ)が生成されましたが、2回目の実行ではカウンタデータファイルのみが生成されました:メタデータは実行ごとに変わらないため、一度だけ書き込む必要があります。

Go 1.20では、「covdata」という新しいツールが導入され、GOCOVERDIRディレクトリからカバレッジデータファイルを読み取り、操作するために使用できます。

Goのcovdataツールはさまざまなモードで実行されます。covdataツール呼び出しの一般的な形式は次のようになります

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

ここで「-i」フラグは、カバレッジ計測されたバイナリの実行から派生した各ディレクトリのリストを提供します(GOCOVERDIRを介して)。

カバレッジプロファイルレポートの作成

このセクションでは、「go tool covdata」を使用してカバレッジデータファイルから人間が読み取れるレポートを生成する方法について説明します。

カバレッジされたステートメントの割合を報告する

各計測パッケージの「カバレッジされたステートメントの割合」メトリックを報告するには、「go tool covdata percent -i=<directory>」コマンドを使用します。上記の実行セクションの例を使用すると:

  1. $ ls somedata
  2. covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
  3. covmeta.c6de772f99010ef5925877a7b05db4cc
  4. $ go tool covdata percent -i=somedata
  5. main coverage: 100.0% of statements
  6. mydomain.com/greetings coverage: 100.0% of statements
  7. $

ここでの「カバレッジされたステートメント」の割合は、go test -coverによって報告されたものと直接対応しています。

レガシーテキスト形式への変換

バイナリカバレッジデータファイルを「go test -coverprofile=<outfile>」によって生成されたレガシーテキスト形式に変換するには、covdata textfmtセレクタを使用できます。生成されたテキストファイルは、「go tool cover -func」または「go tool cover -html」と共に使用して追加のレポートを作成できます。例:

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

マージ

go tool covdata」のmergeサブコマンドを使用して、複数のデータディレクトリからプロファイルをマージできます。

例えば、macOSとWindowsの両方で実行されるプログラムを考えてみましょう。このプログラムの著者は、各オペレーティングシステムでの別々の実行からのカバレッジプロファイルを単一のプロファイルコーパスに結合し、クロスプラットフォームのカバレッジサマリーを生成したいと考えるかもしれません。例えば:

  1. $ ls windows_datadir
  2. covcounters.f3833f80c91d8229544b25a855285890.1025623.1667481441036838252
  3. covcounters.f3833f80c91d8229544b25a855285890.1025628.1667481441042785007
  4. covmeta.f3833f80c91d8229544b25a855285890
  5. $ ls macos_datadir
  6. covcounters.b245ad845b5068d116a4e25033b429fb.1025358.1667481440551734165
  7. covcounters.b245ad845b5068d116a4e25033b429fb.1025364.1667481440557770197
  8. covmeta.b245ad845b5068d116a4e25033b429fb
  9. $ ls macos_datadir
  10. $ mkdir merged
  11. $ go tool covdata merge -i=windows_datadir,macos_datadir -o merged
  12. $

上記のマージ操作は、指定された入力ディレクトリからのデータを結合し、「merged」ディレクトリに新しいマージデータファイルのセットを書き込みます。

パッケージ選択

ほとんどの「go tool covdata」コマンドは、操作の一部としてパッケージ選択を行うための「-pkg」フラグをサポートしています。「-pkg」への引数は、Goコマンドの「-coverpkg」フラグで使用される形式と同じです。例:

  1. $ ls somedata
  2. covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
  3. covmeta.c6de772f99010ef5925877a7b05db4cc
  4. $ go tool covdata percent -i=somedata -pkg=mydomain.com/greetings
  5. mydomain.com/greetings coverage: 100.0% of statements
  6. $ go tool covdata percent -i=somedata -pkg=nonexistentpackage
  7. $

-pkg」フラグを使用して、特定のレポートに関心のあるパッケージのサブセットを選択できます。

よくある質問

私のgo.modファイルに記載されているすべてのインポートパッケージに対してカバレッジ計測をリクエストするにはどうすればよいですか

デフォルトでは、go build -coverはカバレッジのためにすべてのメインモジュールパッケージを計測しますが、メインモジュールの外部のインポート(例えば、標準ライブラリパッケージやgo.modにリストされているインポート)は計測しません。すべての非標準ライブラリ依存関係に対して計測をリクエストする方法の1つは、go listの出力を-coverpkgにフィードすることです。以下は、上記で引用した例のプログラムを使用した例です:

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

GO111MODULE=offモードでgo build -coverを使用できますか?

はい、go build -coverGO111MODULE=offで動作します。GO111MODULE=offモードでプログラムをビルドする場合、コマンドラインでターゲットとして特に指定されたパッケージのみがプロファイリングのために計測されます。-coverpkgフラグを使用して、プロファイルに追加のパッケージを含めます。

私のプログラムがパニックを起こした場合、カバレッジデータは書き込まれますか?

go build -coverでビルドされたプログラムは、os.Exit()を呼び出すか、main.mainから通常に戻る場合にのみ、実行の最後に完全なプロファイルデータを書き出します。プログラムが回復不可能なパニックで終了した場合、またはプログラムが致命的な例外(セグメンテーション違反、ゼロ除算など)に遭遇した場合、実行中に実行されたステートメントのプロファイルデータは失われます。

-coverpkg=mainは私のメインパッケージをプロファイリングのために選択しますか?

  1. ``````bash
  2. $ go list -m
  3. mydomain.com
  4. $ go build -coverpkg=main -o oops.exe .
  5. warning: no packages being built depend on matches for pattern main
  6. $ go build -coverpkg=mydomain.com -o myprogram.exe .
  7. $ mkdir somedata
  8. $ GOCOVERDIR=somedata ./myprogram.exe
  9. I say "Hello, world." and "see ya"
  10. $ go tool covdata percent -i=somedata
  11. mydomain.com coverage: 100.0% of statements
  12. $
  13. `

リソース

  • Go 1.2におけるユニットテストカバレッジの紹介ブログ記事:
    • ユニットテストのカバレッジプロファイリングはGo 1.2リリースの一部として導入されました。詳細についてはこのブログ記事を参照してください。
  • ドキュメント:
    • cmd/goパッケージのドキュメントは、カバレッジに関連するビルドおよびテストフラグを説明しています。
  • 技術的詳細:

用語集

ユニットテスト: 特定のGoパッケージに関連付けられた*_test.goファイル内のテストで、Goのtestingパッケージを利用しています。

統合テスト: 特定のアプリケーションまたはバイナリに対するより包括的で重いテスト。統合テストは通常、プログラムまたはプログラムのセットをビルドし、その後、複数の入力とシナリオを使用してプログラムの一連の実行を行い、Goのtestingパッケージに基づくかどうかにかかわらずテストハーネスの制御下で実行されます。