読者です 読者をやめる 読者になる 読者になる

write ahead log

ロールフォワード用

golangでhttptestを使ってテストする

golang

ちょっとしたコマンドとか作る時にWebAPIを触ろうとすると,
net/httpをよく使うことになる.

テストについてはちょっと調べたんだけどhttp経由のものはやったことがなかった.
net/httpはテストについてもnet/http/httptestがサポートしてくれているのでこれを使うことにする.

余談だけど, 標準でなんでも入っているってのは本当に楽でいい.
ライブラリをあれこれ探したりランタイムを入れて環境構築するのにはもう疲れてきた.
本質からズレているような気がしてくる.

簡単なサンプルは以下の通り. GETリクエストで挨拶をするだけの関数がある.

[sample.go]

package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func remoteHello(domain string) string {
    // /greetingにクエリパラメータgreet=Helloを渡してGet問い合わせする
    res, err := http.Get(domain + "/greeting?greet=Hello")

    // エラー処理
    if err != nil {
        fmt.Println("Error")
        return "error"
    }
    defer res.Body.Close()

    // レスポンスを戻り値にする
    res_str, _ := ioutil.ReadAll(res.Body)
    return string(res_str)
}

これをテストするためのコードが以下の通り.

package main

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

func TestRemoteHello(t *testing.T) {
    // テストサーバを用意する
    // サーバ側でアクセスする側のテストを行う
    ts := httptest.NewServer(http.HandlerFunc(
        func(w http.ResponseWriter, r *http.Request) {
            // URLのアクセスパスが誤っていないかチェック
            if r.URL.Path != "/greeting" {
                t.Fatalf("誤ったアクセスパスでアクセス!")
            }
            // クエリパラメータをチェック
            if r.URL.Query().Get("greet") != "Hello" {
                t.Fatalf("正しく挨拶してない!")
            }
            // レスポンスを設定する
            w.Header().Set("content-Type", "text")
            fmt.Fprintf(w, "world")
            return
        },
    ))
    defer ts.Close()


    // クライアントのコードを呼び出す.
    // アクセスされる側(サーバ)のレスポンスのテストを行う.

    // テストサーバのルートパスはts.URLで取得できます
    res := remoteHello(ts.URL)

    if res != "world" {
        t.Errorf("世界じゃなかった.")
    }
}

ポイントは

  • httptest.NewServerでテストサーバを立てる
  • テストサーバのURLメソッドでテストサーバへのルートパスを手に入れられる

の2つだろうか.

もっと色々できる気もするが,とりあえずこれでダミーのリクエストとレスポンスが作れるので 必要十分かなと.