
こんにちは。よっしーです(^^)
本日は、Go言語の.統合テストのカバレッジついて解説しています。
背景
Go言語でテストを書いていると、「go test -coverprofileでカバレッジが取れるのは知っているけど、統合テストのカバレッジってどうやって測るんだろう?」と疑問に思ったことはありませんか?
公式ドキュメントには、Go 1.20から統合テストのカバレッジ測定がサポートされたことが書かれていますが、英語で書かれている上に、ユニットテストとの違いや具体的な手順の説明が簡潔すぎて、初めて読むと「結局どうすればいいの?」と戸惑ってしまうかもしれません。
この記事では、公式ドキュメントの内容を丁寧な日本語に翻訳し、さらに初心者の方でも理解できるように、ユニットテストと統合テストの違い、なぜ3ステップ必要なのか、そして実際にどのようなコマンドを実行すればよいのかを、具体例を交えて解説していきます。
統合テストのカバレッジ測定は一見難しそうに見えますが、仕組みを理解すれば決して複雑ではありません。実際のアプリケーションでどれだけコードがテストされているかを把握することで、より品質の高いソフトウェア開発ができるようになります。一緒に学んでいきましょう!
レガシーテキスト形式への変換
“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%
$
解説
textfmt モード: テキスト形式への変換
なぜ変換が必要なのか
統合テストのカバレッジデータ(バイナリ形式)を、従来の単体テストで使われていたテキスト形式に変換することで、既存のツールが使えるようになります。
図書館の例え:
- バイナリ形式 = 新しいデジタル蔵書システム(最新だが対応ツールが少ない)
- テキスト形式 = 従来の紙の目録(古いが多くの人が使える)
textfmt= デジタルデータを紙の目録形式に変換
基本的な使い方
コマンド構文
go tool covdata textfmt -i=<入力ディレクトリ> -o=<出力ファイル>
具体例:
# バイナリデータをテキストに変換
go tool covdata textfmt -i=coverage -o=profile.txt
完全な作業フロー
# ステップ1: カバレッジ対応でビルド
go build -cover -o myapp .
# ステップ2: テストを実行してバイナリデータ収集
mkdir coverage
GOCOVERDIR=coverage ./myapp
# ステップ3: バイナリデータをテキスト形式に変換
go tool covdata textfmt -i=coverage -o=profile.txt
# ステップ4: テキストファイルの内容を確認(オプション)
cat profile.txt
# ステップ5: 既存ツールでレポート生成
go tool cover -func=profile.txt # 関数ごとのレポート
go tool cover -html=profile.txt # HTMLレポート
テキスト形式ファイルの構造
プロファイルファイルの内容
mode: set
mydomain.com/myprogram.go:10.13,12.2 1 1
mydomain.com/greetings/greetings.go:3.23,5.2 1 1
各行の意味:
1行目: mode: set
- カバレッジの測定モード
set: 実行されたかどうか(0または1)- 他のモード:
count(実行回数)、atomic(並行実行対応)
2行目以降: カバレッジデータ
mydomain.com/myprogram.go:10.13,12.2 1 1
↑ ↑ ↑ ↑
ファイルパス 位置 文 実行
数 状況
| 要素 | 説明 | 例 |
|---|---|---|
| ファイルパス | ソースファイルの場所 | mydomain.com/myprogram.go |
| 位置情報 | 開始行.開始列,終了行.終了列 | 10.13,12.2 |
| ステートメント数 | このブロックのステートメント数 | 1 |
| 実行状況 | 実行されたか(1=実行、0=未実行) | 1 |
位置情報の詳細
10.13,12.2
↑ ↑ ↑ ↑
│ │ │ └─ 終了列(2列目)
│ │ └──── 終了行(12行目)
│ └─────── 開始列(13列目)
└────────── 開始行(10行目)
実際のコード例:
// myprogram.go
1: package main
2:
3: import "fmt"
4:
5: func main() {
6: message := getMessage()
7: fmt.Println(message)
8: }
9:
10: func getMessage() string {
11: return "Hello, World!"
12: }
プロファイル行 myprogram.go:10.13,12.2 1 1 は:
- 10行目の13列目から始まる(
string {) - 12行目の2列目で終わる(
}) - このブロックには1つのステートメントがある
- 実行された(1)
go tool cover との連携
パターン1: 関数ごとのレポート(-func)
$ go tool cover -func=profile.txt
mydomain.com/greetings/greetings.go:3: Goodbye 100.0%
mydomain.com/myprogram.go:10: getMessage 100.0%
mydomain.com/myprogram.go:5: main 100.0%
total: (statements) 100.0%
出力の読み方:
ファイル名:行番号: 関数名 カバレッジ率
パターン2: HTMLレポート(-html)
# HTMLレポートを生成して自動的にブラウザで開く
go tool cover -html=profile.txt
# HTMLファイルとして保存
go tool cover -html=profile.txt -o=coverage.html
HTMLレポートの特徴:
- 実行されたコードは緑色でハイライト
- 実行されなかったコードは赤色でハイライト
- 実行されなかったコードは灰色(未測定)
- 視覚的にわかりやすい
実践例1: 単純なプログラム
# プログラム
$ cat main.go
package main
import "fmt"
func main() {
fmt.Println(greet("World"))
}
func greet(name string) string {
if name == "" {
return "Hello, Stranger!"
}
return "Hello, " + name + "!"
}
# ビルドと実行
$ go build -cover -o myapp .
$ mkdir coverage
$ GOCOVERDIR=coverage ./myapp
# テキスト形式に変換
$ go tool covdata textfmt -i=coverage -o=profile.txt
# 関数ごとのカバレッジ
$ go tool cover -func=profile.txt
main.go:5: main 100.0%
main.go:9: greet 66.7%
total: (statements) 75.0%
解釈:
main関数: 100%(すべて実行)greet関数: 66.7%(空文字チェックが実行されていない)- 全体: 75%
実践例2: Webアプリケーション
#!/bin/bash
# web-coverage.sh
# 準備
rm -rf coverage
mkdir coverage
# ビルド
go build -cover -o webserver ./cmd/server
# サーバー起動
GOCOVERDIR=coverage ./webserver &
SERVER_PID=$!
sleep 2
# テスト実行
curl http://localhost:8080/api/users
curl http://localhost:8080/api/posts
curl http://localhost:8080/health
# サーバー停止
kill $SERVER_PID
wait $SERVER_PID 2>/dev/null
# テキスト形式に変換
go tool covdata textfmt -i=coverage -o=web-coverage.txt
# HTMLレポート生成
go tool cover -html=web-coverage.txt -o=web-coverage.html
# 関数ごとのレポート
echo "=== 関数ごとのカバレッジ ==="
go tool cover -func=web-coverage.txt
echo ""
echo "HTMLレポートを生成しました: web-coverage.html"
レガシー形式と新形式の比較
単体テスト(従来の方法)
# 直接テキスト形式のプロファイルを生成
go test -coverprofile=coverage.txt
# レポート生成
go tool cover -func=coverage.txt
go tool cover -html=coverage.txt
統合テスト(Go 1.20以降)
# バイナリ形式で収集
go build -cover -o myapp .
GOCOVERDIR=coverage ./myapp
# テキスト形式に変換(←この追加ステップが必要)
go tool covdata textfmt -i=coverage -o=coverage.txt
# レポート生成(ここからは同じ)
go tool cover -func=coverage.txt
go tool cover -html=coverage.txt
メリット:
- 既存の
go tool coverがそのまま使える - HTMLレポートが生成できる
- CIツールとの互換性が保たれる
複数ディレクトリの統合
# 複数のテストスイートを実行
GOCOVERDIR=coverage/unit ./myapp unit-tests
GOCOVERDIR=coverage/integration ./myapp integration-tests
GOCOVERDIR=coverage/e2e ./myapp e2e-tests
# すべてを統合してテキスト形式に変換
go tool covdata textfmt \
-i=coverage/unit,coverage/integration,coverage/e2e \
-o=combined-coverage.txt
# HTMLレポート生成
go tool cover -html=combined-coverage.txt -o=full-report.html
CI/CDパイプラインでの活用
# .github/workflows/coverage.yml
name: Coverage Report
on: [push]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.20
- name: Build with coverage
run: go build -cover -o myapp .
- name: Run integration tests
run: |
mkdir coverage
GOCOVERDIR=coverage ./myapp run-tests
- name: Convert to text format
run: go tool covdata textfmt -i=coverage -o=coverage.txt
- name: Generate HTML report
run: go tool cover -html=coverage.txt -o=coverage.html
- name: Upload coverage report
uses: actions/upload-artifact@v2
with:
name: coverage-report
path: coverage.html
- name: Display coverage
run: go tool cover -func=coverage.txt
トラブルシューティング
問題1: 空のプロファイルファイル
$ go tool covdata textfmt -i=coverage -o=profile.txt
$ cat profile.txt
mode: set
# データがない
原因:
- カバレッジデータが収集されていない
GOCOVERDIRを設定せずに実行した
解決策:
# データを確認
ls coverage/
# 正しく実行し直す
GOCOVERDIR=coverage ./myapp
問題2: go tool coverでエラー
$ go tool cover -func=profile.txt
cover: invalid function coverage line: ...
原因:
- プロファイルファイルが壊れている
- 古い形式のファイル
解決策:
# 再生成
go tool covdata textfmt -i=coverage -o=profile.txt -pkg=./...
問題3: HTMLが正しく表示されない
$ go tool cover -html=profile.txt
# ソースコードが見つからない
原因:
- ソースファイルのパスが変わった
- 元のソースコードがない
解決策:
# カバレッジ収集と同じディレクトリで実行
cd /path/to/project
go tool cover -html=profile.txt
実用的なスクリプト
#!/bin/bash
# generate-full-report.sh
set -e # エラーで停止
# 設定
APP="./myapp"
COVERAGE_DIR="coverage"
PROFILE="profile.txt"
HTML_REPORT="coverage-report.html"
# クリーンアップ
echo "クリーンアップ中..."
rm -rf $COVERAGE_DIR $PROFILE $HTML_REPORT
# ビルド
echo "ビルド中..."
go build -cover -o $APP .
# テスト実行
echo "統合テストを実行中..."
mkdir $COVERAGE_DIR
# 複数シナリオを実行
scenarios=("scenario1" "scenario2" "scenario3")
for scenario in "${scenarios[@]}"; do
echo " - $scenario"
GOCOVERDIR=$COVERAGE_DIR $APP --test=$scenario
done
# テキスト形式に変換
echo "プロファイルを生成中..."
go tool covdata textfmt -i=$COVERAGE_DIR -o=$PROFILE
# 関数ごとのカバレッジを表示
echo ""
echo "=== カバレッジサマリー ==="
go tool cover -func=$PROFILE | tail -1
# 詳細レポート
echo ""
echo "=== 関数ごとの詳細 ==="
go tool cover -func=$PROFILE
# HTMLレポート生成
echo ""
echo "HTMLレポートを生成中..."
go tool cover -html=$PROFILE -o=$HTML_REPORT
echo ""
echo "完了!"
echo " テキストレポート: $PROFILE"
echo " HTMLレポート: $HTML_REPORT"
# カバレッジが閾値を下回ったら警告
COVERAGE=$(go tool cover -func=$PROFILE | tail -1 | awk '{print $3}' | sed 's/%//')
THRESHOLD=80
if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
echo ""
echo "⚠️ 警告: カバレッジが${THRESHOLD}%を下回っています (現在: ${COVERAGE}%)"
exit 1
fi
まとめ
| 項目 | 説明 |
|---|---|
| コマンド | go tool covdata textfmt -i=<dir> -o=<file> |
| 入力 | バイナリカバレッジデータ(GOCOVERDIR) |
| 出力 | テキスト形式プロファイル |
| 互換性 | go tool cover -func、-htmlで使用可能 |
| 用途 | 既存ツールやCIパイプラインとの統合 |
重要なポイント:
textfmtでバイナリ→テキスト変換- 変換後は従来の
go tool coverが使える - HTMLレポートで視覚的に確認できる
- CI/CDパイプラインに組み込みやすい
- 複数ディレクトリを統合可能
次の記事では、さらに高度なcovdataの使い方(マージ、フィルタリングなど)を見ていきましょう。
おわりに
本日は、Go言語の統合テストのカバレッジについて解説しました。

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

コメント