How to check http calls in Go using httptest

I have the following code:

package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "time" ) type twitterResult struct { Results []struct { Text string `json:"text"` Ids string `json:"id_str"` Name string `json:"from_user_name"` Username string `json:"from_user"` UserId string `json:"from_user_id_str"` } } var ( twitterUrl = "http://search.twitter.com/search.json?q=%23UCL" pauseDuration = 5 * time.Second ) func retrieveTweets(c chan<- *twitterResult) { for { resp, err := http.Get(twitterUrl) if err != nil { log.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) r := new(twitterResult) //or &twitterResult{} which returns *twitterResult err = json.Unmarshal(body, &r) if err != nil { log.Fatal(err) } c <- r time.Sleep(pauseDuration) } } func displayTweets(c chan *twitterResult) { tweets := <-c for _, v := range tweets.Results { fmt.Printf("%v:%v\n", v.Username, v.Text) } } func main() { c := make(chan *twitterResult) go retrieveTweets(c) for { displayTweets(c) } } 

I would like to write some tests for this, but I'm not sure how to use the httptest http://golang.org/pkg/net/http/httptest/ package to evaluate some pointers

I came up with this (shamelessly copied from tests for go OAuth https://code.google.com/p/goauth2/source/browse/oauth/oauth_test.go ):

 var request = struct { path, query string // request contenttype, body string // response }{ path: "/search.json?", query: "q=%23Kenya", contenttype: "application/json", body: twitterResponse, } var ( twitterResponse = `{ 'results': [{'text':'hello','id_str':'34455w4','from_user_name':'bob','from_user_id_str':'345424'}]}` ) func TestRetrieveTweets(t *testing.T) { handler := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", request.contenttype) io.WriteString(w, request.body) } server := httptest.NewServer(http.HandlerFunc(handler)) defer server.Close() resp, err := http.Get(server.URL) if err != nil { t.Fatalf("Get: %v", err) } checkBody(t, resp, twitterResponse) } func checkBody(t *testing.T, r *http.Response, body string) { b, err := ioutil.ReadAll(r.Body) if err != nil { t.Error("reading reponse body: %v, want %q", err, body) } if g, w := string(b), body; g != w { t.Errorf("request body mismatch: got %q, want %q", g, w) } } 
+61
go
Apr 22 '13 at 19:18
source share
3 answers

httptest performs two types of tests: response and server

Answer Test:

 func TestHeader3D(t *testing.T) { resp := httptest.NewRecorder() uri := "/3D/header/?" path := "/home/test" unlno := "997225821" param := make(url.Values) param["param1"] = []string{path} param["param2"] = []string{unlno} req, err := http.NewRequest("GET", uri+param.Encode(), nil) if err != nil { t.Fatal(err) } http.DefaultServeMux.ServeHTTP(resp, req) if p, err := ioutil.ReadAll(resp.Body); err != nil { t.Fail() } else { if strings.Contains(string(p), "Error") { t.Errorf("header response shouldn't return error: %s", p) } else if !strings.Contains(string(p), `expected result`) { t.Errorf("header response doen't match:\n%s", p) } } } 

Server test (what you need to use):

 func TestIt(t *testing.T){ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") fmt.Fprintln(w, `{"fake twitter json string"}`) })) defer ts.Close() twitterUrl = ts.URL c := make(chan *twitterResult) go retrieveTweets(c) tweet := <-c if tweet != expected1 { t.Fail() } tweet = <-c if tweet != expected2 { t.Fail() } } 

By the way, you do not need to pass a pointer to r, because it is already a pointer.

 err = json.Unmarshal(body, r) 

EDIT: for my recorder test, I could use my http handler as follows:

 handler(resp, req) 

But my source code does not use the default multiplex (but from Gorilla / mux), and I have a wrapper around the multiplexer, for example. insert server logging and add request context (Gorilla / context), so I had to start with the multiplexer and call ServeHTTP

+79
Apr 26 '13 at 14:36
source

This code fragment was originally found in the GitHub Gist , but trying to apply the concept to one of my projects, I realized that I needed to significantly change the main code, and decided to test these calls using the integration test. using docker and curl.

+9
May 31 '16 at 15:14
source

If you want to test your program, it is often best to write it based on testing. For example, if you retrieved the inner loop of your retrieveTweets function something like this:

 func downloadTweets(tweetsUrl string) (*twitterResult, error) 

You can call it with the URL of the test server that you configured using the httptest package without worrying about sleeping or repeated requests.

+6
Apr 23 '13 at 4:17
source



All Articles