SoFunction
Updated on 2025-03-04

Golang httptest package test tutorial

I really touched me when I first learned about the Golang httptest package. Testing HTTP services in other languages ​​requires a lot of work or references to third-party tools. What is incredible is that the Golang standard library provides a very easy-to-understand test package. This article introduces the use of httptest package and builds better end-to-end testing for your Go http service.

The concept of the httptest package is that it is very easy to simulate http services, that is, simulate response writers and provide them to the http processors, so that it is easy for us to test the http server and client.

This article mainly introduces two specific scenarios using httptest: testing the http server processor and testing the http client.

Test the http server processor

The following is an example to introduce the test of http server. First look at the http service program and convert the request string to capitalization:

package main
import (
    "fmt"
    "log"
    "net/http"
    "net/url"
    "strings"
)
// Req: http://localhost:1234/upper?word=abc
// Res: ABC
func upperCaseHandler(w , r *) {
    query, err := ()
    if err != nil {
        ()
        (w, "invalid request")
        return
    }
    word := ("word")
    if len(word) == 0 {
        ()
        (w, "missing word")
        return
    }
    ()
    (w, (word))
}
func main() {
    ("/upper", upperCaseHandler)
    ((":1234", nil))
}

Now if you want to test the upperCaseHandler logic used by http server, we need to prepare two aspects:

  • Use exposed functions to create an object, NewRequest returns a Request, which can be passed to test.
  • Create with functions, return. ResponseRecorder is

The implementation of this, it records changes for later tests.

Yes, it can be passed to the http server handle, record all processing and write back the response data. The following test program can see how it is implemented:

package main
import (
    "io/ioutil"
    "net/http"
    "net/http/httptest"
    "testing"
)
func TestUpperCaseHandler(t *) {
    req := (, "/upper?word=abc", nil)
    w := ()
    upperCaseHandler(w, req)
    res := ()
    defer ()
    data, err := ()
    if err != nil {
        ("expected error to be nil got %v", err)
    }
    if string(data) != "ABC" {
        ("expected ABC got %v", string(data))
    }
}

In the above example, the request and response are first defined and then passed to the processor for testing. Then check the Result method output of ResponseRecorder:

func (rw *ResponseRecorder) Result() *

Result returns the response generated by the processor. Returns the corresponding content with at least StatusCode, Header, Body, and optionally other content, and may fill more fields in the future, so the caller should not be equal in depth in the test.

Test HTTP client

It is relatively easy to test server processors, especially when testing processor logic, only mocks and objects are required in the test. For HTTP client testing, the situation is a bit complicated. The reason is that it is sometimes not easy to simulate or copy the entire HTTP Server, please see the following example:

package main
import (
    "io/ioutil"
    "net/http"
    "/pkg/errors"
)
type Client struct {
    url string
}
func NewClient(url string) Client {
    return Client{url}
}
func (c Client) UpperCase(word string) (string, error) {
    res, err := ( + "/upper?word=" + word)
    if err != nil {
        return "", (err, "unable to complete Get request")
    }
    defer ()
    out, err := ()
    if err != nil {
        return "", (err, "unable to read response data")
    }
    return string(out), nil
}

The client requires a url, which represents the remote server base address. Then call/upper, bring the input word with it, and finally return the result string to the caller. If the call is unsuccessful, the error object will be returned. In order to test this code, it is necessary to simulate the entire http server logic, or at least respond to the request path:/upper. Use the httptest package to simulate the entire http service, by initializing the local service, listening to the loopback address and returning whatever you want.

use

Generate what we want by calling the function. Indicates the http service, listens to the loopback address and optional port number, and is used to implement end-to-end HTTP testing.

func NewServer(handler ) *Server

NewServer starts and returns a new HTTP service. After the caller completes use, he should call the Close method to end the service. The following is an example:

package main
import (
    "fmt"
    "net/http"
    "net/http/httptest"
    "strings"
    "testing"
)
func TestClientUpperCase(t *) {
    expected := "dummy data"
    svr := ((func(w , r *) {
        (w, expected)
    }))
    defer ()
    c := NewClient()
    res, err := ("anything")
    if err != nil {
        ("expected err to be nil got %v", err)
    }
    // res: expected\r\n
    // due to the http protocol cleanup response
    res = (res)
    if res != expected {
        ("expected res to be %s got %s", expected, res)
    }
}

In the above example, the simulated http server is created using the function, and the custom simulated processor is passed to it, and the same data is always returned. And use the server url as the client requests the url, thus mocking and letting the server return whatever we want to test.

Of course we can modify the processor to return the logic we expect:

func TestClientUpperCase(t *) {
	svr := ((func(w , r *) {
		query, err := ()
		if err != nil {
			()
			(w, "invalid request")
			return
		}
		word := ("word")
		if len(word) > 0 {
			(w, (word))
		} else {
			(w, "no input")
		}
	}))
	defer ()
	expected := "ANYTHING"
	c := NewClient()
	res, err := ("anything")
	if err != nil {
		("expected err to be nil got %v", err)
	}
	// res: expected\r\n
	// due to the http protocol cleanup response
	res = (res)
	if res != expected {
		("expected res to be %s got %s", expected, res)
	}
}

Summarize

This article introduces the httptest package, which can be very convenient to test the http server processing logic and simulate the http server testing client request logic. Due to the very simulation, a set of parameters and expected values ​​can be combined, tested in a cycle and compared the results, which can greatly improve the testing efficiency.

This is the article about the use of Golang httptest package testing tutorial. For more related Go httptest content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!