httptestclient

package module
v0.0.0-...-52c1130 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2023 License: MIT Imports: 12 Imported by: 0

README

Overview

Simplified creating http client calls for testing http servers or handlers.

Cleanly build and execute http requests in tests so that you can focus on what is important.

Basic usage

func Test_Example(t *testing.T) {
    myTestDatabase := map[string]string{"database-key": "Hello"}
    s := httptest.NewServer(ProductionHandler(myTestDatabase))

    resp := httptestclient.New(t).
        Post("/any/%s", "database-key").
        BodyJSON(&Customer{Name: "Bob"}).
        Header("custom", "😊").
        DoSimple(s)

    // default is to allow resp.Status == 2xx so no need to assert
    payload := map[string]string{}
    resp.BodyJSON(&payload)
    if payload["value"] != "Hello Bob 😊" {
        t.Errorf("expected json with name='Hello Bob 😊' got %s", resp.Body)
    }
}

create a new httptestclient, set the .Method, .Url, .Headers, .ExpectedStatusCode as required, then call .Do (to get the http.Response) or .DoSimple to receive just the headers, status and body.

If any part of the construction or execution of the request fails the test will fail, but you don't need to specify this.

The long complicated way

func Test_Example_ToAvoid(t *testing.T) {
    myTestDatabase := map[string]string{"database-key": "Hello"}
    s := httptest.NewServer(ProductionHandler(myTestDatabase))

    buf, err := json.Marshal(Customer{Name: "Bob"})
    if err != nil {
        t.Errorf("failed to marshal request: %v", err)
    }
    req, err := http.NewRequest(http.MethodPost, s.URL+"/any/database-key", bytes.NewReader(buf))
    if err != nil {
        t.Errorf("failed to create request: %v", err)
    }
    req.Header.Set("custom", "😊")
    resp, err := s.Client().Do(req)
    if err != nil {
        t.Errorf("failed to execute request: %v", err)
    }
    if resp.StatusCode < 200 || resp.StatusCode > 299 {
        t.Errorf("expected 2xx OK got %d", resp.StatusCode)
    }
    defer resp.Body.Close()
    buf, err = io.ReadAll(resp.Body)
    if err != nil {
        t.Errorf("failed to read response body: %v", err)
    }
    payload := map[string]string{}
    err = json.Unmarshal(buf, &payload)
    if err != nil {
        t.Errorf("failed to unmarshal response body: %v", err)
    }
    if payload["value"] != "Hello Bob 😊" {
        t.Errorf("expected json with name='Hello Bob 😊' got %s", string(buf))
    }
}

There is so much error handling to make sure the test is valid that is not easy to see what is actually being tested

Documentation

Overview

Package httptestclient generates and executes standard http requests. It follows the basic builder pattern to build and/or execute the request against a httptest.Server Any errors that occur during the build or execute of the request will fail the test so that you can focus on your server not on the http client

Index

Constants

View Source
const ContentTypeApplicationJson = "application/json"

ContentTypeApplicationJson for http header Content-Type

View Source
const UserAgent = "test-http-request"

UserAgent default value

Variables

View Source
var (
	// DefaultContentType when content is detected
	DefaultContentType = ContentTypeApplicationJson
)
View Source
var ErrNilBodyJSON = errors.New("BodyJson requires non nil value")

ErrNilBodyJSON sentinel error

Functions

This section is empty.

Types

type Client

type Client struct {

	// MaxRedirects, (per request) default is 10
	MaxRedirects int
	// contains filtered or unexported fields
}

Client simplifies creating test client http request

func New

func New(t TestingT) *Client

New for testing, finish with Client.Do or Client.DoSimple `t` use `*testing.T` `s` server under test example:

  resp2 := New(t).
		Post("/some-request/%s/resource", id).
		Header("special-header", "magic").
		BodyString(`{"token":"opaque-string"}`).
		Do(server)

func (*Client) BodyBytes

func (c *Client) BodyBytes(body []byte) *Client

BodyBytes to send

func (*Client) BodyJSON

func (c *Client) BodyJSON(payload interface{}) *Client

BodyJSON convert struct to son using json.Marshal

func (*Client) BodyString

func (c *Client) BodyString(body string) *Client

BodyString is a literal string version of the body if the body has a value the content-type will be 'application/json' will be added unless you set an alternative or use ClearHeaders()

func (*Client) BuildRequest

func (c *Client) BuildRequest() *http.Request

BuildRequest a raw unsent request

func (*Client) ClearHeaders

func (c *Client) ClearHeaders() *Client

ClearHeaders removes default http headers, Accept, Content-Type, User-Agent. Must be called before adding other headers

func (*Client) Context

func (c *Client) Context(ctx context.Context) *Client

Context when sending the request, defaults to `context.Context()` if not set

func (*Client) Delete

func (c *Client) Delete(url string, args ...interface{}) *Client

Delete is shorthand for

testClient.Method("DELETE").URL(...)

func (*Client) Do

func (c *Client) Do(server *httptest.Server) *http.Response

Do the http request, http status must either match expected or be success

func (*Client) DoSimple

func (c *Client) DoSimple(server *httptest.Server) SimpleResponse

DoSimple performs as Do but reads any response payload to a string

func (*Client) ExpectRedirectTo

func (c *Client) ExpectRedirectTo(path string) *Client

ExpectRedirectTo a specific url

func (*Client) ExpectedStatusCode

func (c *Client) ExpectedStatusCode(status int) *Client

ExpectedStatusCode for the test to pass. By default, any 2xx will pass otherwise explicitly state the success status do not use this to expect redirects, see ExpectRedirectTo

func (*Client) FormData

func (c *Client) FormData(args ...string) *Client

FormData for posting x-www-form-urlencoded forms args is expected to be pairs of key:values

func (*Client) Get

func (c *Client) Get(url string, args ...interface{}) *Client

Get is shorthand for

testClient.Method("GET").URL(...)

func (*Client) Header

func (c *Client) Header(name, value string, moreValues ...string) *Client

Header for request, can be called multiple times and is additive unless using the same header name, then it overwrites

func (*Client) Method

func (c *Client) Method(method string) *Client

Method to use in request, the default is GET

func (*Client) Patch

func (c *Client) Patch(url string, args ...interface{}) *Client

Patch is shorthand for

testClient.Method("PATCH").URL(...)

func (*Client) Post

func (c *Client) Post(url string, args ...interface{}) *Client

Post is shorthand for

testClient.Method("POST").URL(...)

func (*Client) Put

func (c *Client) Put(url string, args ...interface{}) *Client

Put is shorthand for

testClient.Method("PUT").URL(...)

func (*Client) URL

func (c *Client) URL(url string, args ...interface{}) *Client

URL adds a url using standard formatting as per fmt.Sprintf, default '/'

type SimpleResponse

type SimpleResponse struct {
	Header        http.Header
	Body          string
	Status        int
	RedirectedVia string
	Response      *http.Response
	// contains filtered or unexported fields
}

SimpleResponse simplified status response rather than using the http.Response directly

func (SimpleResponse) BodyJSON

func (r SimpleResponse) BodyJSON(payload interface{})

BodyJSON uses json.Unmarshal to map the Body to the struct

type TestingT

type TestingT interface {
	// Errorf as per testing.T
	Errorf(format string, args ...interface{})
	// FailNow as per testing.T
	FailNow()
}

TestingT allows testing of this test client use *testing.T

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL