🧪

【Go】Goのテストに入門してみた! ~httptest編①~

に公開

はじめに

前回は「Fuzzingテスト」を見ていきました。
今回は「httptest」に入門します。

前回の記事はこちら!
https://zenn.dev/tmyhrn/articles/f329b29e92faa7

この記事でわかること

  • Goの標準パッケージである httptest の概要や役割
  • httptest を使ったHTTPハンドラーのテスト方法

httptestとは?

httptest はGoに標準搭載されているパッケージです。
net/http/httptest が該当します。)
httptest を使うことで、実際にHTTPサーバーを立ち上げることなく、HTTPハンドラーやWebアプリケーションのテストを簡単に行うことができます。

GoのhttptestでGETリクエストをテストする方法

今回はGETメソッドで httptest を使ったハンドラーのテストをしてみます。
フレームワークはEchoを使います。

main_test.go
package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
    
    "github.com/labstack/echo/v4"
)

func helloHandler(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, Echo!")
}

func TestHelloHandler(t *testing.T) {
    e := echo.New()

    req := httptest.NewRequest(http.MethodGet, "/hello", nil)
    rec := httptest.NewRecorder()

    c := e.NewContext(req, rec)
    
    if err := helloHandler(c); err != nil {
        t.Fatalf("handler returned error: %v", err)
    }
    if rec.Code != http.StatusOK {
        t.Errorf("expected status 200, got %d", rec.Code)
    }
    if rec.Body.String() != "Hello, Echo!" {
        t.Errorf("expected body %q, got %q", "Hello, Echo!", rec.Body.String())
    }
}

実行すると、以下のような結果が得られます。

ターミナル
# go test -v

=== RUN   TestHelloHandler
--- PASS: TestHelloHandler (0.00s)
PASS
ok      go-test-practice        0.384s

httptest + Echoハンドラーの実装解説

1. ハンドラーの定義

main_test.go
func helloHandler(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, Echo!")
}

今回は「Hello, Echo!」を出力するシンプルな実装です。

2. Echoインスタンスの作成

main_test.go
e := echo.New()

Echoのルーティングやハンドラーをテストするために必要なインスタンスを作成します。

3. テスト用のリクエストとレスポンスを作成

main_test.go
req := httptest.NewRequest(http.MethodGet, "/hello", nil)
rec := httptest.NewRecorder()

それぞれ以下の役割を果たしています。

  • httptest.NewRequest():擬似リクエストを作成
    1. 第一引数:実施したいHTTPリクエストメソッド
    2. 第二引数:実施したいエンドポイント
    3. 第三引数:リクエストボディ(今回はGETメソッドなのでnil)
  • httptest.NewRecorder():ハンドラーの出力を書き込むための擬似レスポンスライター

4. Echoコンテキストの作成

main_test.go
c := e.NewContext(req, rec)

Echo独自のコンテキストを作成します。
コンテキストにリクエストとレスポンスの疑似オブジェクトを入れることで、実際のリクエストと同様にハンドラーを実行できます。

5. ハンドラーを実行

main_test.go
if err := helloHandler(c); err != nil {
    t.Fatalf("handler returned error: %v", err)
}

ハンドラーにコンテキストを渡し、ハンドラーを実行します。
もしエラーが返された場合はテストを失敗させます。

6. レスポンスのステータスコードを確認

main_test.go
if rec.Code != http.StatusOK {
    t.Errorf("expected status 200, got %d", rec.Code)
}

期待するステータスコードとレスポンスのコードが一致するかをチェックします。
一致しない場合はエラーを返します。

7. レスポンスの本文を確認

main_test.go
if rec.Body.String() != "Hello, Echo!" {
    t.Errorf("expected body %q, got %q", "Hello, Echo!", rec.Body.String())
}

期待する本文とレスポンスの本文が一致するかをチェックします。
一致しない場合はエラーを返します。

まとめ

今回は「httptest」について学びました。

Goの httptest パッケージを使えば、実際にサーバーを立ち上げなくてもHTTPハンドラーの挙動をテストすることができます。
擬似リクエストとレスポンスを作成し、コンテキストに渡すことで、ハンドラーのステータスコードやレスポンス本文を簡単に検証することができます。
この手法を使えば、サーバー起動不要で効率的にハンドラーの動作確認ができ、堅牢なWebアプリケーション開発に役立つということがわかりました。

次回も「httptest」に入門します!

参考

https://pkg.go.dev/net/http/httptest
https://echo.labstack.com/docs/testing
https://future-architect.github.io/articles/20250509a/#APIサーバのハンドラのテストをしたい
https://qiita.com/syukan3/items/3497cd0e1567d11680ef

Discussion