net/httptestでgojiのテストをする

goji でWebアプリを書こうとしていま す。APIサーバーとして使うときに、テストが気になります。

golangは net/http/httptest というhttpのtestを行うパッ ケージが最初からついています。これを使うと簡単にテストを記述できます。

httptest.Serverはlocalのloopbackインタフェースでサーバーを作成します。

(2014/11/20追記): mopemopeさんから「Routingのテストを入れたほうがいいのでは」というご指摘を受けたので、Route設定を別関数に分け、テストからも使うようにしました。

サンプルアプリ

/hello/hoge というURLにアクセスが来たらJSONを返す、という単純なア プリです。

package main

import (
    "encoding/json"
    "fmt"
    "net/http"

    "github.com/zenazn/goji"
    "github.com/zenazn/goji/web"
)

type User struct {
    Id   int64
    Name string
}

func hello(c web.C, w http.ResponseWriter, r *http.Request) {
    u := User{
        Id:   1,
        Name: c.URLParams["name"],
    }

    j, _ := json.Marshal(u)
    fmt.Fprintf(w, string(j))
}

func Route(m *web.Mux) {
    m.Get("/hello/:name", hello)
}

func main() {
    Route(goji.DefaultMux)
    goji.Serve()
}

これに対するテストが以下の感じです。

package main

import (
    "io/ioutil"
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/zenazn/goji/web"
)

func ParseResponse(res *http.Response) (string, int) {
    defer res.Body.Close()
    contents, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }
    return string(contents), res.StatusCode
}

func Test_Hello(t *testing.T) {
    m := web.New()
    Route(m)
    ts := httptest.NewServer(m)
    defer ts.Close()

    res, err := http.Get(ts.URL + "/hello/hoge")
    if err != nil {
        t.Error("unexpected")
    }
    c, s := ParseResponse(res)
    if s != http.StatusOK {
        t.Error("invalid status code")
    }
    if c != `{"Id":1,"Name":"hoge"}` {
        t.Error("invalid response")
    }
}

web.New() でgoji/webのHTTP multiplexerを作成します。あとは、 httptest.NewServer(m)としてあげれば、テスト用サーバーが立ち上がります。 deferでCloseするのを忘れないでください。

なお、ts.URLには、立ち上げたテスト用サーバーのportが入ったURLが http://127.0.0.1:51923 みたいな感じで入っています。

簡単にするためにParseResponseという関数を作っていますが、これは別になく ても構いません。

もっと他にいい方法があれば教えてください。

Comments

comments powered by Disqus