How to test http calls in Go using httptest

后端 未结 3 1762
北恋
北恋 2020-12-04 06:09

I have the following code:

package main

import (
    \"encoding/json\"
    \"fmt\"
    \"io/ioutil\"
    \"log\"
    \"net/http\"
    \"time\"
)

type twitt         


        
相关标签:
3条回答
  • 2020-12-04 06:54

    If you want to test your program, it is often best to write it with testing in mind. For instance, if you extracted the inner loop of your retrieveTweets function into something like this:

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

    You could invoke it with the URL of a test server you've set up using the httptest package without having to worry about the sleeps or repeated requests.

    0 讨论(0)
  • 2020-12-04 07:03

    httptest does two types of tests: response and server

    Response 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 (which is 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()
        }
    }
    

    BTW, you don't need to pass in the pointer of r, because it's already a pointer.

    err = json.Unmarshal(body, r)
    

    EDIT: for my recorder test, I could use my http handler like this:

    handler(resp, req)
    

    But my original code is not using the default mux (but from Gorilla/mux), and I have some wrapping around the mux, e.g. insert server logging, and adding request context (Gorilla/context), so I had to start from mux and call ServeHTTP

    0 讨论(0)
  • 2020-12-04 07:08

    Originally this code snippet was found on GitHub Gist, but while trying to apply the concept to one of my projects I realized that I had to modify the main code significantly that I decided to test these calls using an integration test by using docker and curl.

    0 讨论(0)
提交回复
热议问题