Go言語入門:統合テストのカバレッジ -Vol.3-

スポンサーリンク
Go言語入門:統合テストのカバレッジ -Vol.3- ノウハウ
Go言語入門:統合テストのカバレッジ -Vol.3-
この記事は約10分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

本日は、Go言語の統合テストのカバレッジついて解説しています。

スポンサーリンク

背景

Go言語でテストを書いていると、「go test -coverprofileでカバレッジが取れるのは知っているけど、統合テストのカバレッジってどうやって測るんだろう?」と疑問に思ったことはありませんか?

公式ドキュメントには、Go 1.20から統合テストのカバレッジ測定がサポートされたことが書かれていますが、英語で書かれている上に、ユニットテストとの違いや具体的な手順の説明が簡潔すぎて、初めて読むと「結局どうすればいいの?」と戸惑ってしまうかもしれません。

この記事では、公式ドキュメントの内容を丁寧な日本語に翻訳し、さらに初心者の方でも理解できるように、ユニットテストと統合テストの違い、なぜ3ステップ必要なのか、そして実際にどのようなコマンドを実行すればよいのかを、具体例を交えて解説していきます。

統合テストのカバレッジ測定は一見難しそうに見えますが、仕組みを理解すれば決して複雑ではありません。実際のアプリケーションでどれだけコードがテストされているかを把握することで、より品質の高いソフトウェア開発ができるようになります。一緒に学んでいきましょう!

カバレッジインストルメンテーションされたバイナリの実行

-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つのファイルに注目してください。これらの(バイナリ)ファイルにカバレッジ結果が含まれています。これらのデータファイルから人間が読める結果を生成する方法については、レポート生成に関する次のセクションを参照してください。

GOCOVERDIR 環境変数が設定されていない場合、カバレッジインストルメンテーションされたバイナリは正常に実行されますが、警告が表示されます。例:

$ ./myprogram.exe
warning: GOCOVERDIR not set, no coverage data emitted
I say "Hello, world." and "see ya"
$

解説

カバレッジデータを収集する仕組み

前のセクションで -cover フラグ付きでビルドしたバイナリは、実行すると自動的にカバレッジデータを保存します。ただし、どこに保存するかを指定する必要があります

学校の試験の例え:

  • バイナリ実行 = 試験を受ける
  • カバレッジデータ = 解答用紙
  • GOCOVERDIR = 解答用紙を提出する箱の場所
  • 箱の場所を指定しないと、解答用紙は保存されない(警告が出る)

基本的な実行手順(3ステップ)

ステップ1: カバレッジ対応バイナリをビルド

go build -cover -o myprogram.exe myprogram.go

これで「カバレッジデータを記録できるバイナリ」が作成されます。

ステップ2: カバレッジデータの保存先ディレクトリを作成

mkdir somedata

カバレッジデータを保存するための空のディレクトリを用意します。名前は何でも構いません(coveragecovdataresults など)。

ステップ3: 環境変数を設定してバイナリを実行

GOCOVERDIR=somedata ./myprogram.exe

この1行で何が起こっているか:

GOCOVERDIR=somedata    # この実行だけ環境変数を設定
./myprogram.exe        # プログラムを実行

プログラムが終了すると、somedata ディレクトリにカバレッジデータが自動保存されます。

生成されるファイルの説明

実行後、指定したディレクトリに2種類のファイルが作成されます:

$ ls somedata
covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
covmeta.c6de772f99010ef5925877a7b05db4cc

1. covmeta.* ファイル(メタデータ)

  • 役割: カバレッジ測定の「設計図」
  • 内容: どのパッケージのどのコードを測定したか
  • 例え: 試験の「問題用紙」

2. covcounters.* ファイル(カウンター)

  • 役割: 実際の実行結果
  • 内容: 各コードが何回実行されたか
  • 例え: 試験の「解答用紙」

ファイル名の構造:

covcounters.【ハッシュ値】.【プロセスID】.【タイムスタンプ】
            c6de772f...   2424989       1670252383...

covmeta.【ハッシュ値】
        c6de772f...
  • ハッシュ値: ビルドごとに一意(同じビルドなら同じ値)
  • プロセスID: 実行ごとに異なる(複数回実行を区別)
  • タイムスタンプ: 実行日時

環境変数 GOCOVERDIR の設定方法

方法1: インライン設定(1回だけ有効)

# Linux/Mac
GOCOVERDIR=somedata ./myprogram.exe

# Windows (PowerShell)
$env:GOCOVERDIR="somedata"; .\myprogram.exe

# Windows (コマンドプロンプト)
set GOCOVERDIR=somedata && myprogram.exe

特徴:

  • その1回の実行だけに有効
  • 最もシンプル
  • 推奨される方法

方法2: エクスポート(セッション中ずっと有効)

# Linux/Mac
export GOCOVERDIR=somedata
./myprogram.exe
./myprogram.exe  # 2回目も有効

# Windows (PowerShell)
$env:GOCOVERDIR="somedata"
.\myprogram.exe

特徴:

  • ターミナルセッション中ずっと有効
  • 複数回実行する場合に便利

GOCOVERDIR を設定しないとどうなるか

環境変数を設定せずに実行すると:

$ ./myprogram.exe
warning: GOCOVERDIR not set, no coverage data emitted
I say "Hello, world." and "see ya"

結果:

  • ✅ プログラムは正常に動作する
  • ⚠️ 警告メッセージが表示される
  • ❌ カバレッジデータは保存されない

例え: 試験は受けられるけど、解答用紙の提出先がないので記録されない状態です。

複数回実行してデータを蓄積

統合テストの利点は、複数回の実行でカバレッジを蓄積できることです:

# 1回目: ユーザー登録機能をテスト
GOCOVERDIR=coverage ./myapp register --user=alice

# 2回目: ログイン機能をテスト(同じディレクトリに追加)
GOCOVERDIR=coverage ./myapp login --user=alice

# 3回目: 投稿機能をテスト(同じディレクトリに追加)
GOCOVERDIR=coverage ./myapp post --title="Hello"

# 結果確認
$ ls coverage
covcounters.abc123.10001.1234567890  # 1回目
covcounters.abc123.10002.1234567891  # 2回目
covcounters.abc123.10003.1234567892  # 3回目
covmeta.abc123                        # メタデータ(1つ)

それぞれのファイルが統合される:

  • すべての実行のカバレッジが合算される
  • 最終的に「全体として何%カバーされたか」がわかる

実践例:Webサーバーのテスト

# 1. カバレッジ対応でビルド
go build -cover -o webserver ./cmd/server

# 2. カバレッジデータ保存用ディレクトリ作成
mkdir coverage

# 3. サーバーをバックグラウンドで起動
GOCOVERDIR=coverage ./webserver &
SERVER_PID=$!  # プロセスIDを保存

# 4. 実際のテストを実行
curl http://localhost:8080/api/users
curl http://localhost:8080/api/posts
curl -X POST http://localhost:8080/api/login -d '{"user":"test"}'

# 5. サーバーを停止(この時点でカバレッジデータが保存される)
kill $SERVER_PID

# 6. 結果確認
ls coverage/

重要なポイント: カバレッジデータはプログラム終了時に保存されます。サーバーのような長時間実行プログラムでは、きちんと終了させないとデータが保存されません。

バイナリファイルの扱い

生成されたカバレッジファイルはバイナリ形式です:

$ cat coverage/covmeta.abc123
# 文字化けした内容が表示される(人間には読めない)

人間が読める形式に変換するには: 次のセクションで説明する go tool covdata コマンドを使います。

トラブルシューティング

問題1: 「ディレクトリが存在しない」エラー

$ GOCOVERDIR=notexist ./myapp
panic: open notexist/covmeta.xxx: no such file or directory

解決策:

mkdir notexist  # ディレクトリを先に作成
GOCOVERDIR=notexist ./myapp

問題2: カバレッジファイルが作成されない

チェックリスト:

  1. -cover フラグでビルドしたか?
  2. GOCOVERDIR を設定したか?
  3. ✅ ディレクトリは存在するか?
  4. ✅ ディレクトリへの書き込み権限があるか?
  5. ✅ プログラムが正常に終了したか?(クラッシュしていないか)

問題3: 複数回実行すると古いデータが残る

# 古いデータを削除してから実行
rm -rf coverage/*
GOCOVERDIR=coverage ./myapp

または

# 実行ごとに別のディレクトリを使う
GOCOVERDIR=coverage/run1 ./myapp
GOCOVERDIR=coverage/run2 ./myapp
GOCOVERDIR=coverage/run3 ./myapp

実践的なスクリプト例

シンプルな実行スクリプト

#!/bin/bash

# クリーンアップ
rm -rf coverage
mkdir coverage

# カバレッジ付きでビルド
go build -cover -o myapp .

# 実行
GOCOVERDIR=coverage ./myapp

# 確認
echo "カバレッジファイルが生成されました:"
ls -l coverage/

統合テストスクリプト

#!/bin/bash

# 準備
rm -rf coverage
mkdir coverage
go build -cover -o webserver ./cmd/server

# サーバー起動
GOCOVERDIR=coverage ./webserver &
SERVER_PID=$!

# サーバーの起動を待つ
sleep 2

# テストシナリオ実行
echo "Testing user registration..."
curl -X POST http://localhost:8080/api/register -d '{"user":"alice"}'

echo "Testing login..."
curl -X POST http://localhost:8080/api/login -d '{"user":"alice"}'

echo "Testing API access..."
curl http://localhost:8080/api/data

# クリーンアップ
kill $SERVER_PID
wait $SERVER_PID 2>/dev/null

echo "カバレッジデータが保存されました:"
ls -l coverage/

まとめ

ステップコマンド説明
1. ビルドgo build -cover -o app .カバレッジ対応バイナリを作成
2. ディレクトリ作成mkdir coverageデータ保存先を準備
3. 実行GOCOVERDIR=coverage ./app環境変数を設定して実行
4. 確認ls coverage/ファイルが生成されたか確認

重要なポイント:

  • GOCOVERDIR は必須(設定しないとデータが保存されない)
  • カバレッジデータはプログラム終了時に保存される
  • 複数回実行すると自動的にデータが蓄積される
  • 生成されるファイルはバイナリ形式(次のステップで変換が必要)

次の記事では、これらのバイナリファイルから人間が読めるレポートを生成する方法を見ていきます。

おわりに 

本日は、Go言語の統合テストのカバレッジについて解説しました。

よっしー
よっしー

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

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました