
こんにちは。よっしーです(^^)
本日は、Go言語の統合テストのカバレッジついて解説しています。
背景
Go言語でテストを書いていると、「go test -coverprofileでカバレッジが取れるのは知っているけど、統合テストのカバレッジってどうやって測るんだろう?」と疑問に思ったことはありませんか?
公式ドキュメントには、Go 1.20から統合テストのカバレッジ測定がサポートされたことが書かれていますが、英語で書かれている上に、ユニットテストとの違いや具体的な手順の説明が簡潔すぎて、初めて読むと「結局どうすればいいの?」と戸惑ってしまうかもしれません。
この記事では、公式ドキュメントの内容を丁寧な日本語に翻訳し、さらに初心者の方でも理解できるように、ユニットテストと統合テストの違い、なぜ3ステップ必要なのか、そして実際にどのようなコマンドを実行すればよいのかを、具体例を交えて解説していきます。
統合テストのカバレッジ測定は一見難しそうに見えますが、仕組みを理解すれば決して複雑ではありません。実際のアプリケーションでどれだけコードがテストされているかを把握することで、より品質の高いソフトウェア開発ができるようになります。一緒に学んでいきましょう!
カバレッジプロファイリングのためのバイナリのビルド
カバレッジプロファイルを収集するアプリケーションをビルドするには、アプリケーションバイナリのターゲットに対して 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” コマンドラインフラグを付けてビルドして実行すると、プロファイルに含まれるのは正確に2つのパッケージだけです: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 フラグを追加するだけです:
# 通常のビルド
go build -o myapp .
# カバレッジ測定可能なビルド
go build -cover -o myapp .
何が起こるのか:
- コンパイラがコードに「カバレッジ測定用の仕組み」を埋め込む
- このプロセスを「インストルメンテーション」と呼びます
- 実行時にどのコードが実行されたかを記録できるようになる
レストランの例え:
- 通常のビルド = 普通に料理を提供する厨房
- カバレッジビルド = 各料理に「何回作られたか」をカウントするセンサーを付けた厨房
インストルメンテーション(instrumentation)とは
**instrumentation(インストルメンテーション)**は「計測器を取り付ける」という意味です。
プログラムのコードに「ここが実行されました」と記録する仕組みを自動で埋め込むことを指します。
// 元のコード
func Add(a, b int) int {
return a + b
}
// インストルメンテーション後(概念的なイメージ)
func Add(a, b int) int {
coverageRecorder.Mark("Add function called") // 追加される
return a + b
}
どのパッケージが測定対象になるのか
デフォルトの動作(-cover のみ)
測定される:
- ✅ 自分のプロジェクト(メインモジュール)内のパッケージ
測定されない:
- ❌ 外部ライブラリ(
go.modにある依存パッケージ) - ❌ Go標準ライブラリ(
fmt、ioなど)
サンプルプログラムで理解する
プロジェクト構成:
mydomain.com/ ← メインモジュール(自分のプロジェクト)
├── go.mod
├── myprogram.go ← mainパッケージ
└── greetings/
└── greetings.go ← greetingsパッケージ
外部依存:
rsc.io/quote ← 外部ライブラリ
fmt ← Go標準ライブラリ
go build -cover を実行した場合:
測定対象:
✅ main パッケージ(mydomain.com)
✅ greetings パッケージ(mydomain.com/greetings)
測定対象外:
❌ rsc.io/quote(外部ライブラリ)
❌ fmt(標準ライブラリ)
❌ その他の依存パッケージ
なぜ外部パッケージは含まれないのか
理由:
- 自分のコードの品質を知りたいから
- 外部ライブラリは既にテストされているはず
- 自分が書いたコードのカバレッジが重要
- パフォーマンスの問題
- すべてのパッケージを測定すると処理が重くなる
- ファイルサイズも大きくなる
- 実用性
- 標準ライブラリのカバレッジを知っても意味がない
図書館の例え:
- 自分が書いた本(メインモジュール)の読まれ方を調べたい
- 他の著者の本(外部ライブラリ)は既に評価済み
- すべての本を調べると時間とコストがかかりすぎる
-coverpkg フラグで測定対象をカスタマイズ
特定のパッケージだけを測定したい場合や、外部パッケージも含めたい場合に使います。
構文
go build -cover -coverpkg=パッケージ1,パッケージ2,... -o 出力ファイル名 .
例1: 外部ライブラリも含める
go build -cover -o myapp.exe \
-coverpkg=io,mydomain.com,rsc.io/quote .
この場合の測定対象:
✅ main(mydomain.comのmainパッケージ)
✅ io(標準ライブラリ)
✅ rsc.io/quote(外部ライブラリ)
❌ mydomain.com/greetings(明示的に指定していない!)
重要な注意点: -coverpkg を使うと、指定したパッケージだけが測定対象になります。デフォルトの「メインモジュール全体」という動作は無効化されます。
例2: メインモジュール全体を指定
# メインモジュールのすべてのパッケージを測定
go build -cover -coverpkg=mydomain.com/... -o myapp.exe .
... は「このパス以下のすべて」を意味します。
実際の使い分け
ケース1: 通常の開発(デフォルトで十分)
go build -cover -o myapp .
- 自分のコードだけ測定
- 最もシンプル
- ほとんどの場合これで十分
ケース2: 特定のパッケージに絞りたい
# APIハンドラーだけ測定したい
go build -cover -coverpkg=mydomain.com/api/handlers -o myapp .
ケース3: 外部ライブラリの使い方を確認したい
# 自分のプロジェクト + 特定の外部ライブラリ
go build -cover -coverpkg=mydomain.com/...,github.com/external/lib -o myapp .
実践例:Webアプリケーション
# プロジェクト構成
mywebapp/
├── main.go
├── handlers/
│ ├── user.go
│ └── post.go
├── models/
│ └── database.go
└── utils/
└── helper.go
# 例1: すべて測定(デフォルト)
go build -cover -o webapp .
→ main, handlers, models, utils すべて測定
# 例2: ハンドラーだけ測定
go build -cover -coverpkg=mywebapp/handlers -o webapp .
→ handlers パッケージのみ測定
# 例3: ハンドラーとモデルだけ測定
go build -cover -coverpkg=mywebapp/handlers,mywebapp/models -o webapp .
→ handlers と models だけ測定
トラブルシューティング
問題1: 自分のパッケージが測定されない
# ❌ 間違い
go build -cover -coverpkg=io,fmt -o myapp .
# 自分のパッケージを指定し忘れている
# ✅ 正解
go build -cover -coverpkg=mydomain.com/...,io,fmt -o myapp .
問題2: バイナリサイズが大きすぎる
# インストルメンテーションによってサイズが増加
# 本番環境では -cover なしでビルド
# 開発/テスト用
go build -cover -o myapp-test .
# 本番用
go build -o myapp .
まとめ
| 項目 | 説明 |
|---|---|
| 基本コマンド | go build -cover -o バイナリ名 . |
| デフォルト動作 | メインモジュール内のパッケージのみ測定 |
| カスタマイズ | -coverpkg で測定対象を明示的に指定 |
| 注意点 | -coverpkg を使うとデフォルト動作が無効化される |
| ベストプラクティス | 通常はデフォルトで十分。特別な理由がなければ -coverpkg は不要 |
次の記事では、ビルドしたバイナリを実際に実行してカバレッジデータを収集する方法を見ていきます。
おわりに
本日は、Go言語の統合テストのカバレッジについて解説しました。

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)

コメント