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という関数を作っていますが、これは別になくても構いません。
もっと他にいい方法があれば教えてください。