Goのテストのいろは[テストの重要性]

## はじめに

ソフトウェア開発においてテストは品質を保証する重要なプロセスです。  
Goには、標準ライブラリでテスト機能が備わっており、簡単にユニットテストやテスト駆動開発（TDD）を実践できます。
ちょうど現在進行形でテストを調べたり書いたりしていたので簡単にまとめておこうと思います。

**対象読者**
- Goのテストを基礎から学びたい方
- テストの重要性を理解し、開発に活かしたい方
- 実践的なテストの書き方を知りたい方

**目次**
1. テストの重要性について語る
   - テストの目的
   - テストを書くメリット
2. Goの標準テスト機能
   - Goの `testing` パッケージ
   - 基本的なテストの書き方
3. よく使うテストのテンプレート
   - テーブル駆動テスト
   - モックを使ったテスト
   - `httptest` を使った HTTP テスト
4. まとめ

---

## 1. テストの重要性について語る

#### **1.1 テストの目的**

そもそもテストの目的は、コードの品質を保証し、バグを防ぐことです。
開発初期にテストを導入することで、以下のようなメリットがあります。

#### **1.2 テストを書くメリット**

| メリット | 説明 |
|----------|------|
| **バグの早期発見** | コードの動作を事前に確認できる |
| **コードの保守性向上** | 変更を加えても動作が保証される |
| **開発スピードの向上** | デバッグの手間を減らせる |
| **ドキュメントとして機能** | テストを見れば関数の意図がわかる |

---

## 2. Goの標準テスト機能

#### **2.1 Goの`testing`パッケージ**

Goには`testing`パッケージが標準で用意されており、簡単にテストを記述できます。

**テストファイルの命名規則**
- **`_test.go` をファイル名の末尾につける**（例：`math_test.go`）
- **`go test` コマンドで実行可能**

#### **2.2 基本的なテストの書き方**

**math.go（テスト対象の関数）**
```go
package math

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

**math_test.go（テストファイル）**
```go
package math

import (
    "testing"
)

func TestAdd(t *testing.T) {
    result := Add(2, 3)
    expected := 5
    if result != expected {
        t.Errorf("Expected %d but got %d", expected, result)
    }
}
```

**テストの実行**
```sh
go test ./...
```

---

## 3. よく使うテストのテンプレート

#### **3.1 テーブル駆動テスト（Table-Driven Tests）**

Goでは複数のテストケースを一括で実行する「テーブル駆動テスト」がよく使われます。

```go
func TestAddTableDriven(t *testing.T) {
    cases := []struct {
        a, b, expected int
    }{
        {1, 2, 3},
        {2, 3, 5},
        {10, 20, 30},
    }

    for _, c := range cases {
        result := Add(c.a, c.b)
        if result != c.expected {
            t.Errorf("Expected %d but got %d", c.expected, result)
        }
    }
}
```

#### **3.2 モックを使ったテスト**

依存関係をモック化することで、外部システムに依存せずにテストを実行できます。

```go
type MockRepository struct{}

func (m *MockRepository) GetUser(id int) string {
    return "TestUser"
}

func TestGetUser(t *testing.T) {
    mockRepo := &MockRepository{}
    result := mockRepo.GetUser(1)
    expected := "TestUser"
    if result != expected {
        t.Errorf("Expected %s but got %s", expected, result)
    }
}
```

#### **3.3 `httptest`を使ったHTTPテスト**

GoにはHTTP サーバーの動作をテストするための`httptest`パッケージが用意されています。

```go
package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func handler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("Hello, World!"))
}

func TestHandler(t *testing.T) {
    req := httptest.NewRequest("GET", "http://localhost:8080", nil)
    rec := httptest.NewRecorder()
    handler(rec, req)

    if rec.Code != http.StatusOK {
        t.Errorf("Expected status %d but got %d", http.StatusOK, rec.Code)
    }
    if rec.Body.String() != "Hello, World!" {
        t.Errorf("Unexpected body: %s", rec.Body.String())
    }
}
```

---

## 4. まとめ

| 項目 | 説明 |
|------|------|
| **Goの`testing`パッケージ** | 標準機能でユニットテストを実行可能 |
| **テーブル駆動テスト** | 複数のテストケースをまとめて記述する方法 |
| **モックテスト** | 外部依存を排除してテストを実施する方法 |
| **`httptest`を使ったHTTPテスト** | GoのHTTPサーバーの動作を確認する方法 |

初学者も上級者もみんなテストはしっかり目に書こう覚えよう！
テストマスターへの第一歩としてこの記事が読まれますように！