0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Go】test -coverでカバレッジを計測・可視化する実践ガイド

Posted at

こんにちは!フリーランスエンジニアのこたろうです。
今回は、Goのテストカバレッジについて、実践的な知見を共有します。

なぜカバレッジを計測するのか?

テストカバレッジとは、コードがテストによってどの程度カバーされているかを示す指標です。
これを計測する理由は:

  • バグの早期発見
  • コードの品質維持
  • テスト漏れの防止

基本的な使い方

1. カバレッジの計測

# 基本的な実行方法
go test -cover

# 詳細な結果を出力
go test -cover -v

# カバレッジファイルの生成
go test -coverprofile=coverage.out

2. カバレッジレポートの可視化

# HTMLレポートの生成
go tool cover -html=coverage.out -o coverage.html

# ターミナルでの表示
go tool cover -func=coverage.out

実践的な例

テスト対象のコード

// calc/calc.go
package calc

func Add(a, b int) int {
    return a + b
}

func Subtract(a, b int) int {
    return a - b
}

func Multiply(a, b int) int {
    return a * b
}

func Divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("division by zero")
    }
    return a / b, nil
}

テストコード

// calc/calc_test.go
package calc

import (
    "testing"
)

func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive numbers", 2, 3, 5},
        {"negative numbers", -2, -3, -5},
        {"zero", 0, 0, 0},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result := Add(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

func TestDivide(t *testing.T) {
    tests := []struct {
        name        string
        a, b        int
        expected    int
        expectError bool
    }{
        {"normal division", 6, 2, 3, false},
        {"division by zero", 6, 0, 0, true},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            result, err := Divide(tt.a, tt.b)
            if tt.expectError && err == nil {
                t.Error("expected error but got none")
            }
            if !tt.expectError && err != nil {
                t.Errorf("unexpected error: %v", err)
            }
            if !tt.expectError && result != tt.expected {
                t.Errorf("Divide(%d, %d) = %d; want %d", tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

カバレッジレポートの読み方

func単位のレポート

$ go tool cover -func=coverage.out
calc/calc.go:3:     Add         100.0%
calc/calc.go:7:     Subtract    0.0%
calc/calc.go:11:    Multiply    0.0%
calc/calc.go:15:    Divide      100.0%
total:              (statements) 66.7%

この結果から分かること:

  • Add関数は100%カバー
  • Subtract関数は未テスト
  • Multiply関数は未テスト
  • Divide関数は100%カバー
  • 全体のカバレッジは66.7%

カバレッジ向上のコツ

  1. テーブル駆動テストの活用
func TestMultiply(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive", 2, 3, 6},
        {"negative", -2, 3, -6},
        {"zero", 0, 5, 0},
    }
    // ...
}
  1. エッジケースのテスト
func TestDivide_EdgeCases(t *testing.T) {
    tests := []struct {
        name        string
        a, b        int
        expected    int
        expectError bool
    }{
        {"max int", math.MaxInt64, 1, math.MaxInt64, false},
        {"min int", math.MinInt64, 1, math.MinInt64, false},
        {"division by zero", 1, 0, 0, true},
    }
    // ...
}
  1. エラーケースのテスト
func TestDivide_Error(t *testing.T) {
    _, err := Divide(1, 0)
    if err == nil {
        t.Error("expected error for division by zero")
    }
}

CI/CDでの活用

GitHub Actionsでの例

name: Go Test Coverage

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    
    - name: Set up Go
      uses: actions/setup-go@v2
      with:
        go-version: 1.19
    
    - name: Run Tests with Coverage
      run: |
        go test -coverprofile=coverage.out ./...
        go tool cover -func=coverage.out
    
    - name: Upload Coverage Report
      uses: actions/upload-artifact@v2
      with:
        name: coverage-report
        path: coverage.out

まとめ

テストカバレッジを計測・可視化することで:

  1. コードの品質を定量的に評価可能
  2. テスト漏れを早期発見
  3. リファクタリング時の安全性確保

ただし、カバレッジ100%を目指すことが必ずしも最適とは限りません。
コストとベネフィットを考慮しながら、適切なカバレッジ目標を設定することが重要です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?