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

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

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

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

スポンサーリンク

背景

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

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

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

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

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

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

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

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

$ ls somedata
covcounters.c6de772f99010ef5925877a7b05db4cc.2424989.1670252383678349347
covmeta.c6de772f99010ef5925877a7b05db4cc
$ go tool covdata percent -i=somedata
    main    coverage: 100.0% of statements
    mydomain.com/greetings  coverage: 100.0% of statements
$

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


解説

レポート生成の基本

前のセクションまでで、カバレッジデータ(バイナリファイル)を収集しました。このセクションでは、そのデータを人間が理解できる形に変換します。

料理の例え:

  • カバレッジデータ = レジのデータ(機械的な記録)
  • レポート生成 = 売上報告書の作成(人間が読める形式)

percent モード: カバレッジ率を表示

基本的な使い方

go tool covdata percent -i=<データディレクトリ>

具体例:

$ go tool covdata percent -i=coverage
    main    coverage: 85.0% of statements
    mydomain.com/handlers    coverage: 72.5% of statements
    mydomain.com/models      coverage: 90.0% of statements

出力の読み方

出力形式

    <パッケージ名>    coverage: <割合>% of statements

各要素の意味:

要素説明
パッケージ名測定されたパッケージmain, mydomain.com/handlers
coverageカバレッジの意味
割合カバーされたコードの割合85.0%, 100.0%
of statementsステートメント単位での測定

ステートメント(statements)とは

ステートメントとは、プログラムの「実行可能な1つの命令」のことです。

ステートメントの例

func Add(a, b int) int {
    result := a + b     // ステートメント1
    return result       // ステートメント2
}
// この関数には2つのステートメントがある
func CheckAge(age int) string {
    if age >= 20 {           // ステートメント1(条件判定)
        return "adult"       // ステートメント2
    }
    return "minor"           // ステートメント3
}
// この関数には3つのステートメントがある

カバレッジ率の計算方法

計算式:

カバレッジ率 = (実行されたステートメント数 / 全ステートメント数) × 100

具体例

// handlers/user.go
package handlers

func HandleUser(action string) string {
    if action == "create" {           // ステートメント1(常に実行)
        return createUser()           // ステートメント2(actionが"create"の時)
    } else if action == "delete" {    // ステートメント3(常に実行)
        return deleteUser()           // ステートメント4(actionが"delete"の時)
    }
    return "unknown"                  // ステートメント5(その他の時)
}
// 全部で5つのステートメント

テストケース1: action=”create” のみ実行

GOCOVERDIR=coverage ./myapp --action=create
  • 実行されたステートメント: 1, 2, 3(3個)
  • カバレッジ: 3/5 = 60%

テストケース2: action=”create” と “delete” を実行

GOCOVERDIR=coverage ./myapp --action=create
GOCOVERDIR=coverage ./myapp --action=delete
  • 実行されたステートメント: 1, 2, 3, 4(4個)
  • カバレッジ: 4/5 = 80%

テストケース3: すべてのパターンを実行

GOCOVERDIR=coverage ./myapp --action=create
GOCOVERDIR=coverage ./myapp --action=delete
GOCOVERDIR=coverage ./myapp --action=other
  • 実行されたステートメント: 1, 2, 3, 4, 5(5個)
  • カバレッジ: 5/5 = 100%

実際の例で理解する

例1: シンプルなプログラム

# プログラムの準備
$ cat main.go
package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

func greet(name string) string {
    return "Hello, " + name
}

# ビルド
$ go build -cover -o myapp .

# 実行
$ mkdir coverage
$ GOCOVERDIR=coverage ./myapp

# レポート生成
$ go tool covdata percent -i=coverage
    main    coverage: 50.0% of statements

なぜ50%なのか?

  • main()関数は実行された
  • greet()関数は呼ばれていない
  • 2つの関数のうち1つしか実行されていない

例2: 複数パッケージのプログラム

# プロジェクト構成
myproject/
├── main.go
├── handlers/
│   └── api.go
└── models/
    └── user.go

# ビルドと実行
$ go build -cover -o myapp .
$ GOCOVERDIR=coverage ./myapp

# レポート
$ go tool covdata percent -i=coverage
    main                      coverage: 100.0% of statements
    myproject/handlers        coverage: 75.0% of statements
    myproject/models          coverage: 50.0% of statements

解釈:

  • mainパッケージ: すべてのコードが実行された(100%)
  • handlersパッケージ: 一部のAPIハンドラーが使われていない(75%)
  • modelsパッケージ: 半分のモデル操作しか実行されていない(50%)

go test -cover との比較

go test -cover(単体テスト)

$ go test -cover
PASS
coverage: 85.0% of statements
ok      mypackage    0.123s

特徴:

  • テストコード(*_test.go)を実行
  • パッケージ単位での測定
  • 簡単で素早い

go tool covdata percent(統合テスト)

$ go tool covdata percent -i=coverage
    main                coverage: 85.0% of statements
    mypackage/handlers  coverage: 72.5% of statements

特徴:

  • 実際のバイナリを実行
  • 複数パッケージを同時に測定
  • より実際の使用に近い

重要なポイント: 両方のツールは同じ計算方法を使用しているため、カバレッジの数値は直接比較できます。

実践例:Webアプリケーション

#!/bin/bash
# coverage-test.sh

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

# ビルド
echo "ビルド中..."
go build -cover -o webapp ./cmd/server

# Webサーバーを起動
echo "サーバー起動中..."
GOCOVERDIR=coverage ./webapp &
SERVER_PID=$!

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

# 各種エンドポイントをテスト
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 "サーバー停止中..."
kill $SERVER_PID
wait $SERVER_PID 2>/dev/null

# カバレッジレポート生成
echo "カバレッジレポート:"
go tool covdata percent -i=coverage

実行結果の例:

ビルド中...
サーバー起動中...
APIテスト実行中...
サーバー停止中...
カバレッジレポート:
    main                      coverage: 100.0% of statements
    webapp/handlers           coverage: 66.7% of statements
    webapp/middleware         coverage: 50.0% of statements
    webapp/models             coverage: 80.0% of statements

カバレッジ率の目安

カバレッジ率評価説明
90-100%優秀ほぼすべてのコードがテストされている
70-90%良好主要な機能はカバーされている
50-70%改善の余地あり重要な部分が抜けている可能性
50%未満要改善多くのコードがテストされていない

注意点:

  • 100%が必ずしも良いとは限らない
  • エラーハンドリングなど、実行が難しい部分もある
  • 重要なのは「重要なコードがテストされているか」

複数実行の統合例

# 異なるシナリオで実行
GOCOVERDIR=coverage ./myapp scenario1
GOCOVERDIR=coverage ./myapp scenario2
GOCOVERDIR=coverage ./myapp scenario3

# 統合されたカバレッジ率を表示
$ go tool covdata percent -i=coverage
    main    coverage: 95.0% of statements

仕組み:

  • scenario1: 30%のコードをカバー
  • scenario2: 40%のコードをカバー
  • scenario3: 50%のコードをカバー
  • 統合結果: 重複を除いて95%(一部が複数のシナリオで実行される)

トラブルシューティング

問題1: 0%と表示される

$ go tool covdata percent -i=coverage
    main    coverage: 0.0% of statements

考えられる原因:

  • プログラムがすぐにクラッシュした
  • メインロジックが実行されていない
  • データファイルが正しく生成されていない

確認方法:

# データファイルを確認
ls -la coverage/

# プログラムが正常終了したか確認
echo $?  # 0なら正常終了

問題2: パッケージが表示されない

$ go tool covdata percent -i=coverage
    main    coverage: 100.0% of statements
# 他のパッケージが表示されない

原因:

  • -coverビルド時にそのパッケージが含まれていない
  • そのパッケージのコードが実行されていない

解決策:

# すべてのパッケージを明示的に含める
go build -cover -coverpkg=./... -o myapp .

問題3: 複数ディレクトリの統合

# 個別に見ると
$ go tool covdata percent -i=coverage/test1
    main    coverage: 50.0% of statements

$ go tool covdata percent -i=coverage/test2
    main    coverage: 60.0% of statements

# 統合すると
$ go tool covdata percent -i=coverage/test1,coverage/test2
    main    coverage: 80.0% of statements  # 単純な足し算ではない

理由: 重複する部分があるため、単純に足し算にはならない。

実用的なスクリプト

#!/bin/bash
# full-coverage-report.sh

# 設定
APP="./myapp"
COVERAGE_DIR="coverage"

# 初期化
rm -rf $COVERAGE_DIR
mkdir $COVERAGE_DIR

# ビルド
echo "=== ビルド ==="
go build -cover -o $APP .

# 複数シナリオを実行
scenarios=("basic" "advanced" "error-cases")

for scenario in "${scenarios[@]}"; do
    echo "=== シナリオ: $scenario ==="
    GOCOVERDIR=$COVERAGE_DIR $APP --test=$scenario
done

# 総合レポート
echo ""
echo "=== 総合カバレッジレポート ==="
go tool covdata percent -i=$COVERAGE_DIR

# パッケージごとの詳細が必要な場合の判定
echo ""
read -p "詳細レポートを表示しますか? (y/n) " answer
if [ "$answer" = "y" ]; then
    go tool covdata func -i=$COVERAGE_DIR
fi

まとめ

項目説明
コマンドgo tool covdata percent -i=<dir>
出力パッケージごとのカバレッジ率
単位ステートメント(実行可能な命令)
計算(実行されたステートメント / 全ステートメント) × 100
go test同じ計算方法で互換性あり

重要なポイント:

  • percentモードで素早くカバレッジ率を確認
  • パッケージごとの数値が一目でわかる
  • go test -coverと同じ計算方法
  • 複数回の実行結果が自動的に統合される

次の記事では、より詳細なレポート(関数ごとのカバレッジなど)の生成方法を見ていきます。

おわりに 

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

よっしー
よっしー

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

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

コメント

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