AAA
AAA

Reputation: 2032

Serve multiple handlers with httptest to mock multiple requests

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(...)?

Upvotes: 11

Views: 8457

Answers (2)

jonasl
jonasl

Reputation: 353

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()

Upvotes: 15

Rossiar
Rossiar

Reputation: 2564

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.

Upvotes: 5

Related Questions