備忘録、はじめました。

作業したこと忘れないようにメモっておきます。

httptestでWriteHeaderができなかった話

はじめに goでhttpのhandlerのテストを書いているときに詰まったところを書きます。 詰まったところは、httptest.NewRecoder()の再利用ができなかったことです。 正確には、再利用する方法はあるかもしれないがよくわからなかったので、再度NewRecoder()を呼び出して、新規作成した、で解決しました。

内容

package mytest                                                                    
 
import (
    "bytes"
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "testing"
)
 
func TestOverride(t *testing.T) {
    handler := http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
        var js map[string]interface{}
        decoder := json.NewDecoder(req.Body)
        if err := decoder.Decode(&js); err == nil {
            if js["msg"] == "error" {
                res.WriteHeader(http.StatusBadRequest)
                res.Write([]byte(`{"result": false}`))
            } else {
                res.WriteHeader(http.StatusOK)
                res.Write([]byte(`{"result": true}`))
            }
        }
    })
 
    // 1: StatusOK
    jsons := `{"msg": "test"}`
    w := httptest.NewRecorder()
    r, err := newRequest([]byte(jsons), "POST", "application/json")
    if err != nil {
        t.Errorf("%s", err)
    }
 
    handler.ServeHTTP(w, r)
    if w.Code != http.StatusOK {
        t.Errorf("Expected status code is 200 but got %d", w.Code)
    }
 
    // 2: BadRequest error code
    jsons = `{"msg": "error"}`
    w = httptest.NewRecorder() // ここで再度NewRecoder()を呼ぶ
 
    r, err = newRequest([]byte(jsons), "POST", "application/json")
    if err != nil {
        t.Errorf("%s", err)
    }
 
    handler.ServeHTTP(w, r)
    if w.Code == http.StatusOK {
        t.Errorf("Expected status code is NOT 200 but got %d", w.Code)
    }
}
 
func newRequest(data []byte, method string, c string) (*http.Request, error) {
    req, err := http.NewRequest(
        method,
        "",
        bytes.NewBuffer([]byte(data)),
    )
    req.Header.Set("Content-Type", c)
    return req, err
}

上記は、テストが通ります

はじめは、コメント部分をw.Body.Reset()をすれば大丈夫なのかなぁと安易にやったのですが、そうするとHeader部分への上書きはできませんでした。おそらく、GOの公式ドキュメントに記載されている内容なのかと思います。したがって、w.Body.Reset()で行うと、2回目のBadRequestのエラーを期待するのですが200が返ってくる結果となってしまいます。