
こんにちは。よっしーです(^^)
本日は、Go言語の.統合テストのカバレッジついて解説しています。
背景
Go言語でテストを書いていると、「go test -coverprofileでカバレッジが取れるのは知っているけど、統合テストのカバレッジってどうやって測るんだろう?」と疑問に思ったことはありませんか?
公式ドキュメントには、Go 1.20から統合テストのカバレッジ測定がサポートされたことが書かれていますが、英語で書かれている上に、ユニットテストとの違いや具体的な手順の説明が簡潔すぎて、初めて読むと「結局どうすればいいの?」と戸惑ってしまうかもしれません。
この記事では、公式ドキュメントの内容を丁寧な日本語に翻訳し、さらに初心者の方でも理解できるように、ユニットテストと統合テストの違い、なぜ3ステップ必要なのか、そして実際にどのようなコマンドを実行すればよいのかを、具体例を交えて解説していきます。
統合テストのカバレッジ測定は一見難しそうに見えますが、仕組みを理解すれば決して複雑ではありません。実際のアプリケーションでどれだけコードがテストされているかを把握することで、より品質の高いソフトウェア開発ができるようになります。一緒に学んでいきましょう!
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
$
解説
外部依存パッケージのカバレッジ測定
問題: デフォルトでは外部パッケージが測定されない
通常のgo build -coverでは:
測定される:
✅ 自分のプロジェクト(メインモジュール)
測定されない:
❌ 標準ライブラリ(fmt, io, netなど)
❌ 外部ライブラリ(go.modに記載されている依存関係)
レストランの例え:
- 自分の店(メインモジュール)の売上は記録される
- 仕入れ先(外部依存)の売上は記録されない
解決策: すべての依存関係を測定対象にする
外部ライブラリも含めて測定したい場合の手順を見ていきましょう。
ステップバイステップ解説
ステップ1: 依存パッケージのリストを生成
go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' -deps . | paste -sd "," > pkgs.txt
このコマンドを分解して理解する:
パート1: go list
go list -deps .
意味:
- プロジェクトが依存しているすべてのパッケージをリスト表示
.= カレントディレクトリ(プロジェクトルート)-deps= 依存関係も含める
出力例(一部):
fmt
io
net/http
mydomain.com
mydomain.com/greetings
rsc.io/quote
rsc.io/sampler
golang.org/x/text/language
パート2: -f (フォーマット指定)
go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' -deps .
意味:
-f= 出力フォーマットを指定{{if not .Standard}}= 標準ライブラリでない場合のみ{{.ImportPath}}= パッケージのインポートパスを出力{{end}}= if文の終わり
.Standardとは:
true= 標準ライブラリ(fmt, io など)false= 外部パッケージ
フィルタ後の出力:
mydomain.com
mydomain.com/greetings
rsc.io/quote
rsc.io/sampler
golang.org/x/text/language
golang.org/x/text/internal/tag
標準ライブラリ(fmt, ioなど)が除外されています。
パート3: paste -sd ","
... | paste -sd ","
意味:
paste= 行を結合するコマンド-s= すべての行を1行にまとめる-d ","= 区切り文字としてカンマを使用
結果:
mydomain.com,mydomain.com/greetings,rsc.io/quote,rsc.io/sampler,golang.org/x/text/language,golang.org/x/text/internal/tag
パート4: > pkgs.txt
... > pkgs.txt
意味:
- 結果をファイル
pkgs.txtに保存
pkgs.txtの内容:
mydomain.com,mydomain.com/greetings,rsc.io/quote,rsc.io/sampler,golang.org/x/text/language,golang.org/x/text/internal/tag
ステップ2: パッケージリストを使ってビルド
go build -o myprogram.exe -coverpkg=`cat pkgs.txt` .
このコマンドの意味:
-coverpkg=`cat pkgs.txt`
↑
pkgs.txtの内容を読み込んで-coverpkgに渡す
実際に実行されるコマンド(展開後):
go build -o myprogram.exe \
-coverpkg=mydomain.com,mydomain.com/greetings,rsc.io/quote,rsc.io/sampler,golang.org/x/text/language,golang.org/x/text/internal/tag \
.
これで、メインモジュールだけでなく、すべての外部依存パッケージもカバレッジ測定の対象になります。
ステップ3: 通常通り実行とレポート生成
# 実行
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
外部パッケージ(rsc.io/quote、golang.org/x/text/languageなど)のカバレッジも表示されています!
完全なスクリプト例
#!/bin/bash
# build-with-full-coverage.sh
echo "=== すべての依存パッケージを含むカバレッジビルド ==="
# ステップ1: 非標準ライブラリパッケージのリストを生成
echo "依存パッケージリストを生成中..."
go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' -deps . | paste -sd "," > pkgs.txt
echo "対象パッケージ:"
cat pkgs.txt | tr ',' '\n'
# ステップ2: カバレッジ対応でビルド
echo ""
echo "ビルド中..."
go build -cover -o myapp -coverpkg=`cat pkgs.txt` .
# ステップ3: 実行
echo ""
echo "テスト実行中..."
rm -rf coverage
mkdir coverage
GOCOVERDIR=coverage ./myapp
# ステップ4: レポート生成
echo ""
echo "=== カバレッジレポート ==="
go tool covdata percent -i=coverage
# クリーンアップ
rm pkgs.txt
echo ""
echo "完了!"
Windows環境での対応
Windowsではpasteコマンドが使えないので、PowerShellで対応します:
# PowerShell版
# ステップ1: パッケージリストを生成
go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' -deps . | Out-File -Encoding ASCII temp.txt
$packages = (Get-Content temp.txt) -join ','
$packages | Out-File -Encoding ASCII pkgs.txt
# ステップ2: ビルド
$pkgList = Get-Content pkgs.txt
go build -cover -o myapp.exe -coverpkg=$pkgList .
# ステップ3: 実行
New-Item -ItemType Directory -Force -Path coverage
$env:GOCOVERDIR="coverage"
.\myapp.exe
# ステップ4: レポート
go tool covdata percent -i=coverage
# クリーンアップ
Remove-Item temp.txt, pkgs.txt
より簡単な方法(ワンライナー)
# Linux/Mac
go build -cover -o myapp \
-coverpkg=$(go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' -deps . | paste -sd ",") \
.
# または、標準ライブラリも含めてすべて測定(非推奨)
go build -cover -o myapp \
-coverpkg=$(go list -deps . | paste -sd ",") \
.
なぜ標準ライブラリは除外するのか
標準ライブラリを含める場合
# 標準ライブラリも含める(.Standardチェックなし)
go list -f '{{.ImportPath}}' -deps . | paste -sd "," > pkgs.txt
go build -cover -coverpkg=`cat pkgs.txt` -o myapp .
問題点:
- ビルド時間が非常に長くなる
- 標準ライブラリは大量のコードがある
- すべてをインストルメンテーションすると時間がかかる
- バイナリサイズが巨大になる
- カバレッジ測定コードが大量に埋め込まれる
- 実行速度が遅くなる
- すべてのコードがカバレッジ記録を行う
- 実用的な価値が低い
- 標準ライブラリのカバレッジを知っても意味がない
- 自分で変更できるコードではない
推奨: 標準ライブラリは除外し、自分のコードと直接の依存パッケージだけを測定対象にする。
実践例: Webアプリケーション
#!/bin/bash
# webapp-full-coverage.sh
PROJECT="mywebapp"
APP="./webapp"
echo "=== $PROJECT のフルカバレッジテスト ==="
# クリーンアップ
rm -rf coverage
# 依存パッケージリスト生成
echo "依存パッケージを収集中..."
go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' -deps . | paste -sd "," > deps.txt
echo "測定対象パッケージ数:"
cat deps.txt | tr ',' '\n' | wc -l
# ビルド
echo ""
echo "カバレッジ対応でビルド中(時間がかかる場合があります)..."
go build -cover -o $APP -coverpkg=`cat deps.txt` ./cmd/server
# サーバー起動
echo ""
echo "Webサーバー起動中..."
mkdir coverage
GOCOVERDIR=coverage $APP &
SERVER_PID=$!
sleep 3
# テストリクエスト
echo "APIテスト実行中..."
curl -s http://localhost:8080/api/users > /dev/null
curl -s http://localhost:8080/api/posts > /dev/null
curl -s http://localhost:8080/health > /dev/null
# サーバー停止
echo ""
echo "サーバー停止中..."
kill $SERVER_PID
wait $SERVER_PID 2>/dev/null
# レポート生成
echo ""
echo "=== カバレッジレポート ==="
echo ""
echo "【自分のコード】"
go tool covdata percent -i=coverage -pkg=$PROJECT/...
echo ""
echo "【外部依存】"
go tool covdata percent -i=coverage | grep -v "^ $PROJECT"
echo ""
echo "【全体】"
go tool covdata percent -i=coverage
# HTMLレポート
echo ""
echo "詳細HTMLレポート生成中..."
go tool covdata textfmt -i=coverage -o full-coverage.txt
go tool cover -html=full-coverage.txt -o full-coverage.html
echo ""
echo "完了!"
echo " HTMLレポート: full-coverage.html"
# クリーンアップ
rm deps.txt
特定の外部パッケージだけ測定
# 自分のコード + 特定の外部ライブラリだけ
MY_PACKAGES="mydomain.com/..."
EXTERNAL_LIBS="github.com/gin-gonic/gin,github.com/lib/pq"
go build -cover -o myapp \
-coverpkg="$MY_PACKAGES,$EXTERNAL_LIBS" \
.
トラブルシューティング
問題1: ビルドが非常に遅い
# 依存パッケージが多すぎる可能性
cat pkgs.txt | tr ',' '\n' | wc -l
# 100以上だと時間がかかる
解決策:
# 自分のコードと重要な依存だけに絞る
go build -cover -o myapp \
-coverpkg=mydomain.com/...,重要な外部パッケージ \
.
問題2: バイナリサイズが巨大
$ ls -lh myapp
-rwxr-xr-x 1 user staff 150M myapp # 通常の10倍以上!
原因: 多くのパッケージをインストルメンテーションしている
対策:
# 開発/テスト用とリリース用を分ける
# テスト用(カバレッジあり、大きい)
go build -cover -coverpkg=... -o myapp-test .
# リリース用(カバレッジなし、小さい)
go build -o myapp .
問題3: 実行が遅い
原因: カバレッジ測定のオーバーヘッド
対策:
- 本番環境ではカバレッジビルドを使わない
- 必要最小限のパッケージだけ測定
まとめ
| 項目 | 説明 |
|---|---|
| デフォルト動作 | メインモジュールのみ測定 |
| 外部依存も測定 | -coverpkgで明示的に指定 |
| パッケージリスト生成 | go listで自動生成可能 |
| 標準ライブラリ | 通常は除外(測定しても意味がない) |
| 注意点 | ビルド時間・サイズ・実行速度に影響 |
重要なポイント:
go listで依存パッケージリストを自動生成- 標準ライブラリは通常除外(
{{if not .Standard}}) - すべての依存を測定するとオーバーヘッドが大きい
- 実用的には自分のコード+重要な依存だけ測定するのが良い
- 本番環境ではカバレッジビルドを使用しない
おわりに
本日は、Go言語の統合テストのカバレッジについて解説しました。

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

コメント