Documentation ¶
Overview ¶
Package mockhttp helps you to mock network behaviour for testing against http stack.
Basic Usage ¶
To mock the transport for whatever test you want to run with "http" library, you may override the response with some of the utils like mockhttp.StaticResponseRT:
mocktransport := mockhttp.StaticResponseRT("hello world", "text/plain") mockhttp.UseTransport(mocktransport) ... // resp.Body will always be "hello world", no matter the URL or method resp, err := http.Get("http://whatever.com") ... mochhttp.RestoreTransport() // resp.Body will be normal resp, err := http.Get("http://whatever.com") ...
Override Multiple Sites Behaviour ¶
You may mux different response for different URL host name.
mux := mockhttp.MuxRoundTripper{} mux.AddFunc("www.google.com", mockhttp.StaticResponseRT("fake google", "text/plain")) mux.AddFunc("www.facebook.com", mockhttp.StaticResponseRT("fake facebook", "text/plain")) // "*" for setting fallback http.RoundTripper mux.AddFunc("*", mockhttp.TransportErrorRT(fmt.Errorf("no connection to host"))) mockhttp.UseTransport(mocktransport) ... // resp.Body will be "fake google" resp, err := http.Get("http://www.google.com/helloAPI") // resp.Body will be "fake facebook" resp, err := http.Get("http://www.facebook.com/helloAPI") // will always return error: "no connection to host" resp, err := http.Get("http://www.archive.org/helloAPI") ... mochhttp.RestoreTransport()
Use Without Overriding DefaultTransport ¶
MuxRoundTripper also can be used directly to create client.
mux := mockhttp.MuxRoundTripper{} ... mux.GetClient().Post("http://foobar.com", strings.NewReader("some+data"))
Partial Override ¶
You can partially override the round trip like this:
mux := mockhttp.MuxRoundTripper{} mux.AddFunc("www.google.com", mockhttp.StaticResponseRT("fake google", "text/plain")) mux.AddFunc("www.facebook.com", mockhttp.StaticResponseRT("fake facebook", "text/plain")) // "*" for setting fallback http.RoundTripper mux.Add("*", http.DefaultTransport) client := mux.GetClient() ...
Index ¶
- func RestoreTransport()
- func UseTransport(rt http.RoundTripper)
- type Middleware
- type MiddlewareFunc
- type MuxRoundTripper
- func (mux MuxRoundTripper) Add(host string, rt http.RoundTripper)
- func (mux MuxRoundTripper) AddFunc(host string, fn RoundTripperFunc)
- func (mux MuxRoundTripper) Get(host string) (http.RoundTripper, error)
- func (mux MuxRoundTripper) NewClient() *http.Client
- func (mux MuxRoundTripper) RoundTrip(r *http.Request) (*http.Response, error)
- type ResponseModifier
- type RoundTripperFunc
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RestoreTransport ¶
func RestoreTransport()
RestoreTransport restore the http.DefaultTransport to the one before last call of UseTransport().
func UseTransport ¶
func UseTransport(rt http.RoundTripper)
UseTransport use the given roundtripper as the http.DefaultTransport, and store away the current http.DefaultTransport for restoration.
Example (Simple) ¶
package main import ( "fmt" "io/ioutil" "net/http" "github.com/yookoala/mockhttp" ) func main() { mock := mockhttp.StaticResponseRT("hello world", "text/plain") mockhttp.UseTransport(&mock) resp, _ := http.Get("https://www.google.com") content, _ := ioutil.ReadAll(resp.Body) fmt.Printf("%s", content) mockhttp.RestoreTransport() }
Output: hello world
Types ¶
type Middleware ¶
type Middleware interface {
Wrap(http.RoundTripper) http.RoundTripper
}
Middleware warps an http.RoundTripper and modify the input / output behaviour.
func Chain ¶
func Chain(middlewares ...Middleware) Middleware
Chain wraps the middlware, from outter-most to inner-most, into a combined middleware.
func UseResponseModifier ¶
func UseResponseModifier(modifiers ...ResponseModifier) Middleware
UseResponseModifier converts a function / multiple functions that fulfills ResponseModifier signature into one Middleware.
If more that 1 modifer is provided, they will be chained from first to last. That means the response and error of inner http.RoundTripper will be the input of the first modifer. Then the output of first modifier will be input of the second modifer. So on and so forth until last one.
type MiddlewareFunc ¶
type MiddlewareFunc func(http.RoundTripper) http.RoundTripper
MiddlewareFunc turns a simple function value into Middleware implementation.
func (MiddlewareFunc) Wrap ¶
func (fn MiddlewareFunc) Wrap(inner http.RoundTripper) http.RoundTripper
Wrap implements Middleware
type MuxRoundTripper ¶
type MuxRoundTripper map[string]http.RoundTripper
MuxRoundTripper mux http.RoundTripper by the request's URL.Host field
Example ¶
package main import ( "fmt" "io/ioutil" "net/http" "strings" "github.com/yookoala/mockhttp" ) func main() { // a mock transport layer for testing your API calls / resource download mock := mockhttp.NewMuxRoundTripper() mock.Add("api.service1.com", mockhttp.StaticResponseRT(`{"status": "OK", "cool": true}`, "application/json")) mock.Add("api.service2.com", mockhttp.StaticResponseRT(`{"status": "OK", "cool": true}`, "application/json")) mock.Add("api.service3.com", mockhttp.ServerErrorRT(http.StatusInternalServerError)) mock.Add("mycdn-service.com", mockhttp.FileSystemRT("./testdata")) mock.Add("*", mockhttp.TransportErrorRT(fmt.Errorf("no network"))) // as fallback // simply produces http.Client with the MuxRoundTripper as transport client := mock.NewClient() var resp *http.Response var body []byte var err error // ordinary http.NewRequest routine req, _ := http.NewRequest("GET", "https://api.service1.com/some/endpoint", nil) resp, _ = client.Do(req) body, _ = ioutil.ReadAll(resp.Body) fmt.Printf("result 1 - %s\n", body) // directly use http.Client methods resp, _ = client.Get("https://api.service1.com/some/endpoint") body, _ = ioutil.ReadAll(resp.Body) fmt.Printf("result 2 - %s\n", body) // POST with http.Client method resp, _ = client.Post("https://api.service2.com/some/endpoint", "application/json", strings.NewReader(`{"submit": true}`)) body, _ = ioutil.ReadAll(resp.Body) fmt.Printf("result 3 - %s\n", body) // POST to an endpoint with mock server error resp, _ = client.Post("https://api.service3.com/some/endpoint", "application/json", strings.NewReader(`{"submit": true}`)) body, _ = ioutil.ReadAll(resp.Body) fmt.Printf("result 4 - %s\n", body) // GET a text file, in local file system, with content "hello world" resp, _ = client.Get("https://mycdn-service.com/test.txt") body, _ = ioutil.ReadAll(resp.Body) fmt.Printf("result 5 - %s\n", body) // GET an external service with mock transport, // which will be handled by "*" host handler. _, err = client.Get("https://api.google.com/some/endpoint") fmt.Printf("result 6 - %s\n", err.Error()) }
Output: result 1 - {"status": "OK", "cool": true} result 2 - {"status": "OK", "cool": true} result 3 - {"status": "OK", "cool": true} result 4 - Internal Server Error result 5 - hello world result 6 - Get https://api.google.com/some/endpoint: no network
func NewMuxRoundTripper ¶
func NewMuxRoundTripper() MuxRoundTripper
NewMuxRoundTripper returns a new NewMuxRoundTripper
func (MuxRoundTripper) Add ¶
func (mux MuxRoundTripper) Add(host string, rt http.RoundTripper)
Add an http.RoundTripper to the mux with reference to the host. Please note that a fallback http.RoundTripper can be set with host = "*"
func (MuxRoundTripper) AddFunc ¶
func (mux MuxRoundTripper) AddFunc(host string, fn RoundTripperFunc)
AddFunc add an RoundTripperFunc to the mux with reference to the host Please note that a fallback http.RoundTripper can be set with host = "*"
func (MuxRoundTripper) Get ¶
func (mux MuxRoundTripper) Get(host string) (http.RoundTripper, error)
Get the http.RoundTripper for the given host
func (MuxRoundTripper) NewClient ¶
func (mux MuxRoundTripper) NewClient() *http.Client
NewClient returns a new http.Client with the mux as transport
type ResponseModifier ¶
ResponseModifier implements Middleware by modifying http.Response and/or error output of inner http.RoundTripper output
func ResponseAddHeader ¶
func ResponseAddHeader(key, value string) ResponseModifier
ResponseAddHeader adds the response, if presents, header with given key-value pair
func ResponseSetHeader ¶
func ResponseSetHeader(key, value string) ResponseModifier
ResponseSetHeader sets the response, if presents, header with given key-value pair
func ResponseSetStatus ¶
func ResponseSetStatus(status int) ResponseModifier
ResponseSetStatus sets the response, if presents, status code to the given status
func (ResponseModifier) Wrap ¶
func (modifier ResponseModifier) Wrap(inner http.RoundTripper) http.RoundTripper
Wrap implements Middleware
type RoundTripperFunc ¶
RoundTripperFunc is a simplified way to implement http.RoundTripper
func FileSystemRT ¶
func FileSystemRT(root string) RoundTripperFunc
FileSystemRT implements http.RoundTripper by returning contents of files in a given folder (as defined as `root`).
Example ¶
package main import ( "fmt" "io/ioutil" "net/http" "github.com/yookoala/mockhttp" ) func main() { client := &http.Client{ Transport: mockhttp.FileSystemRT("./testdata"), } resp, _ := client.Get("https://www.google.com/persons/2.json") content, _ := ioutil.ReadAll(resp.Body) fmt.Printf("result 1: %s\n", content) resp, _ = client.Get("https://www.facebook.com/persons/") content, _ = ioutil.ReadAll(resp.Body) fmt.Printf("result 2: %s\n", content) }
Output: result 1: Not Found result 2: Forbidden
func HandlerRT ¶
func HandlerRT(handler http.Handler) RoundTripperFunc
HandlerRT directly inject an http.Handler to the RoundTripper. You may directly test your handler in this mocked transport.
Example ¶
package main import ( "fmt" "io/ioutil" "net/http" "github.com/yookoala/mockhttp" ) func main() { // some http.Handler you want to test with handler := http.NewServeMux() handler.HandleFunc("/item/1", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) fmt.Fprint(w, "content of item 1") }) handler.HandleFunc("/item/", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusForbidden) fmt.Fprint(w, http.StatusText(http.StatusForbidden)) }) client := &http.Client{ Transport: mockhttp.HandlerRT(handler), } resp, _ := client.Get("https://something.com/item/1") content, _ := ioutil.ReadAll(resp.Body) fmt.Printf("result 1: %s\n", content) resp, _ = client.Get("https://something.com/item/2") content, _ = ioutil.ReadAll(resp.Body) fmt.Printf("result 2: %s\n", content) }
Output: result 1: content of item 1 result 2: Forbidden
func ServerErrorRT ¶
func ServerErrorRT(status int) RoundTripperFunc
ServerErrorRT always return a server response of the supplied status code with nil error.
Example ¶
package main import ( "fmt" "io/ioutil" "net/http" "github.com/yookoala/mockhttp" ) func main() { client := &http.Client{ Transport: mockhttp.ServerErrorRT(http.StatusForbidden), } resp, _ := client.Get("https://www.google.com") content, _ := ioutil.ReadAll(resp.Body) fmt.Printf("result 1: %s\n", content) resp, _ = client.Get("https://www.facebook.com") content, _ = ioutil.ReadAll(resp.Body) fmt.Printf("result 2: %s\n", content) }
Output: result 1: Forbidden result 2: Forbidden
func StaticResponseRT ¶
func StaticResponseRT(content, contentType string) RoundTripperFunc
StaticResponseRT returns an http.RoundTripper that returns the same response body no matter what the request is.
Example ¶
package main import ( "fmt" "io/ioutil" "net/http" "github.com/yookoala/mockhttp" ) func main() { client := &http.Client{ Transport: mockhttp.StaticResponseRT("hello world", "text/plain"), } resp, _ := client.Get("http://whatever.com") content, _ := ioutil.ReadAll(resp.Body) fmt.Printf("%s\n", content) }
Output: hello world
func TransportErrorRT ¶
func TransportErrorRT(err error) RoundTripperFunc
TransportErrorRT always return nil server response wtih the supplied error
Example ¶
package main import ( "fmt" "net/http" "github.com/yookoala/mockhttp" ) func main() { client := &http.Client{ Transport: mockhttp.TransportErrorRT(fmt.Errorf("domain not found")), } _, err := client.Get("https://www.google.com") fmt.Printf("result 1: %s\n", err.Error()) _, err = client.Post("https://www.facebook.com", "text/plain", nil) fmt.Printf("result 2: %s\n", err.Error()) }
Output: result 1: Get https://www.google.com: domain not found result 2: Post https://www.facebook.com: domain not found