├── .gitignore ├── LICENSE ├── README.md ├── mockhttp_test.go ├── mockrequest.go └── mockresponsewriter.go /.gitignore: -------------------------------------------------------------------------------- 1 | /mockhttp.test 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Tommi Virtanen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mockhttp -- Go package for unit testing HTTP serving 2 | 3 | Unit testing HTTP services written in Go means you need to call their 4 | `ServeHTTP` receiver. For this, you need something that fulfills the 5 | `http.ResponseWriter` interface, and you need to populate a 6 | `http.Request` struct with suitable-looking data. `mockhttp.go` 7 | helps you do these tasks, without excessive copy-pasting. 8 | 9 | See `mockhttp_test.go` for an example of usage. 10 | -------------------------------------------------------------------------------- /mockhttp_test.go: -------------------------------------------------------------------------------- 1 | package mockhttp_test 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "strings" 7 | "testing" 8 | 9 | "github.com/tv42/mockhttp" 10 | ) 11 | 12 | func hello(w http.ResponseWriter, req *http.Request) { 13 | if req.Method != "GET" { 14 | w.Header().Add("Allow", "GET") 15 | http.Error(w, "Only GET supported.", http.StatusMethodNotAllowed) 16 | return 17 | } 18 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") 19 | w.WriteHeader(http.StatusOK) 20 | w.Write([]byte("Hello, world.\n")) 21 | } 22 | 23 | func TestGET(t *testing.T) { 24 | handler := http.HandlerFunc(hello) 25 | req := mockhttp.NewRequest(t, "GET", "http://foo.example.com/bar", nil) 26 | req.Header.Set("Content-Type", "text/plain; charset=utf-8") 27 | respw := httptest.NewRecorder() 28 | handler.ServeHTTP(respw, req) 29 | wantHdr := make(http.Header) 30 | wantHdr.Add("Content-Type", "text/plain; charset=utf-8") 31 | mockhttp.CheckResponse(t, respw, http.StatusOK, wantHdr, "Hello, world.\n") 32 | } 33 | 34 | func TestPUT(t *testing.T) { 35 | handler := http.HandlerFunc(hello) 36 | body := strings.NewReader(`foo`) 37 | req := mockhttp.NewRequest(t, "PUT", "http://foo.example.com/bar", body) 38 | req.Header.Set("Content-Type", "text/plain; charset=utf-8") 39 | respw := httptest.NewRecorder() 40 | handler.ServeHTTP(respw, req) 41 | wantHdr := make(http.Header) 42 | wantHdr.Add("Content-Type", "text/plain; charset=utf-8") 43 | wantHdr.Add("Allow", "GET") 44 | mockhttp.CheckResponse(t, respw, http.StatusMethodNotAllowed, wantHdr, "Only GET supported.\n") 45 | } 46 | -------------------------------------------------------------------------------- /mockrequest.go: -------------------------------------------------------------------------------- 1 | package mockhttp 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "testing" 7 | ) 8 | 9 | // NewRequest is like http.NewRequest, but calls t.Fatal on error. 10 | func NewRequest(t testing.TB, method, url string, body io.Reader) *http.Request { 11 | req, err := http.NewRequest(method, url, body) 12 | if err != nil { 13 | t.Fatalf("Bug in test: cannot construct http.Request from method=%q, url=%q, body=%#v: %s", method, url, body, err) 14 | } 15 | return req 16 | } 17 | -------------------------------------------------------------------------------- /mockresponsewriter.go: -------------------------------------------------------------------------------- 1 | package mockhttp 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | // CheckResponse checks that the http response matches expectations, 11 | // and calls t.Error if not. 12 | func CheckResponse(t *testing.T, w *httptest.ResponseRecorder, wantStatus int, wantHeaders http.Header, wantBody string) (ok bool) { 13 | ok = true 14 | if w.Code != wantStatus { 15 | t.Errorf("Bad HTTP status: got %d want %d", w.Code, wantStatus) 16 | ok = false 17 | } 18 | if !reflect.DeepEqual(w.HeaderMap, wantHeaders) { 19 | t.Errorf("Bad HTTP response headers: %v", w.HeaderMap) 20 | ok = false 21 | } 22 | respBody := w.Body.String() 23 | if respBody != wantBody { 24 | t.Errorf("Bad HTTP response body: %q", respBody) 25 | ok = false 26 | } 27 | return 28 | } 29 | --------------------------------------------------------------------------------