Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serve multiple handlers with httptest to mock multiple requests

Tags:

go

I've googled all over for this but can't find anything.

I have a struct that takes in a http.Client and it sends several GET requests. In my tests I want to mock the responses so it's not sending real requests.

Currently I've figured out how to only serve 1 request, like this:

     ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        file, err := os.Open("./testdata/1.html")
        if err != nil {
            t.Error(err)
        }
        bytes, err := ioutil.ReadAll(file)
        if err != nil {
            t.Error(err)
        }
        w.Write(bytes)
    }))

   ts.Client() // Now I can inject this client into my struct.

So once that response is mocked out and the http client is performs a new request, my tests are sending out real requests after that.

How do I allow for several handlers so I can mock several responses upon calling http.Client.Get(...)?

like image 534
AAA Avatar asked Jul 10 '18 01:07

AAA


2 Answers

Since the original question uses httptest.NewServer - you can register a ServeMux on the httptest.Server function, and then you can add several routes to that mux:

mux := http.NewServeMux()

mux.HandleFunc("/someroute/", func(res http.ResponseWriter, req *http.Request) {
    ...do some stuff...
})
mux.HandleFunc("/someotherroute/", func(res http.ResponseWriter, req *http.Request) {
    ...do other stuff...
})

ts := httptest.NewServer(mux)
defer ts.Close()
like image 51
jonasl Avatar answered Sep 23 '22 13:09

jonasl


ServeMux.Handle can be used to setup a server to handle multiple requests like in this example.

package main

import (
    "log"
    "net/http"
)

const addr = "localhost:12345"

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/hello", HandleHello)
    // other handlers can be assigned to separate paths
    log.Printf("Now listening on %s...\n", addr)
    server := http.Server{Handler: mux, Addr: addr}
    log.Fatal(server.ListenAndServe())
}

func HandleHello(w http.ResponseWriter, r *http.Request) {
    log.Printf("Hello!")
}

But to be honest you probably just want to abstract the http.Client behind an interface that you've created, and then stub that with a test implementation that returns exactly what you want. By doing this you avoid the overhead of http communication in your tests.

like image 31
Rossiar Avatar answered Sep 25 '22 13:09

Rossiar