golden

package module
v0.10.1 Latest Latest
Warning

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

Go to latest
Published: Jan 21, 2022 License: Apache-2.0 Imports: 19 Imported by: 0

README

Golden is a small library to help with testing using golden files. Its main purpose (but not only one) is to provide an easy way to describe HTTP request / response as YAML files.

Go Report Card GoDoc

Installation

go get github.com/rzajac/golden

Usage

Asserting

Lets say we have a golden file looking like this:

bodyType: json
body: |
    { "key1": "val1" }

How to use it in test.

func Test_Assert(t *testing.T) {
    // --- Given --- 
    gld := golden.File(golden.Open(t, "testdata/file.yaml", nil))
    
    // --- When ---
    data := []byte(`{
        "key1": "val1"
    }`)
    
    // --- Then --- 
    gld.Assert(data)
}

Because the bodyType was set to json the data in the test doesn't have to be formatted exactly the same way as it's in the golden file. The library is smart enough to compare data represented as JSON not the strings.

If you need exact match set bodyType to text.

Unmarshalling

type Data struct {
    Key1 string `json:"key1"`
}

func Test_Unmarshal(t *testing.T) {
    // --- Given ---
    gld := golden.File(golden.Open(t, "../testdata/file.yaml", nil))

    // --- When ---
    data := &Data{}
    gld.Unmarshal(data)

    // --- Then ---
    if data.Key1 != "val1" {
        t.Errorf("expected `%s` got `%s`", "val1", data.Key1)
    }
}

In this case golden file body will be unmarshalled (using json.Unmarshal) to structure Data. Any errors during unmarshalling will be handled by Unmarshal method.

Testing HTTP request / response

Golden file describing the HTTP request and response:

request:
    method: POST
    path: /some/path
    query: key0=val0&key1=val1
    headers:
        - 'Authorization: Bearer token'
        - 'Content-Type: application/json'
    bodyType: json
    body: |
        {
          "key2": "val2"
        }

response:
    statusCode: 200
    headers:
        - 'Content-Type: application/json'
    bodyType: json
    body: |
        { "success": true }

Example test using golden file:

func Test_Endpoint(t *testing.T) {
    // --- Given ---
    pth := "testdata/request.yaml"
    gld := golden.Exchange(golden.Open(t, pth, nil))

    // Setup mocks.
    srvH, mckS := SrvMock()
    mckS.On("CheckUserAccess", "token").Return(true, nil)

    // Prepare request recorder.
    rec := httptest.NewRecorder()

    // --- When ---
    srvH.ServeHTTP(rec, gld.Request.Request())

    // --- Then ---
    mckS.AssertExpectations(t)
    gld.Response.Assert(rec.Result())
}

Golden files as templates

Golden files can also be used as Go templates when more dynamic approach is needed.

request:
    method: POST
    path: /some/path
    query: key0=val0&key1=val1
    headers:
        - 'Authorization: Bearer {{ .token }}'
        - 'Content-Type: application/json'
    bodyType: json
    body: |
        {
          "key2": "val2"
        }

response:
    statusCode: 200
    headers:
        - 'Content-Type: application/json'
    bodyType: json
    body: |
        { "success": true }
func Test_Endpoint(t *testing.T) {
    // --- Given ---
    token := GetTestToken()
    tplD := make(golden.Map).Add("token", token)
    tpl := "testdata/request.yaml"
    gld := golden.Exchange(golden.Open(t, tpl, tplD))

    // Setup mocks.
    srvH, mckS := SrvMock()
    mckS.On("CheckUserAccess", token).Return(true, nil)

    // Prepare request recorder.
    rec := httptest.NewRecorder()

    // --- When ---
    srvH.ServeHTTP(rec, gld.Request.Request())

    // --- Then ---
    mckS.AssertExpectations(t)
    gld.Response.Assert(rec.Result())
}

Check out the documentation to see full API.

License

Apache License, Version 2.0

Documentation

Index

Constants

View Source
const (
	// TypeText represents golden file text body type (default).
	TypeText = "text"

	// TypeJSON represents golden file JSON body type.
	TypeJSON = "json"
)

Golden file body type.

Variables

View Source
var ErrUnknownUnmarshaler = errors.New("unknown unmarshaler")

ErrUnknownUnmarshaler represents an error when unmarshaler for golden file body cannot be found.

Functions

func TplDelims added in v0.9.0

func TplDelims(left, right string) tplOpt

TplDelims sets the template action delimiters to the specified strings.

Types

type Exchange added in v0.0.14

type Exchange struct {
	// HTTP request.
	Request *Request `yaml:"request"`

	// HTTP response.
	Response *Response `yaml:"response"`
	// contains filtered or unexported fields
}

Exchange represents HTTP request / response exchange.

func NewExchange added in v0.0.17

func NewExchange(t T, r io.Reader) *Exchange

NewExchange returns new instance of HTTP request / response Exchange.

func (*Exchange) Assert added in v0.6.0

func (ex *Exchange) Assert(host string) (*http.Request, *http.Response)

Assert makes the request described in the golden file to host and asserts the response matches. It returns constructed request and received response in case further assertions need to be done.

func (*Exchange) WriteTo added in v0.0.17

func (ex *Exchange) WriteTo(w io.Writer) (int64, error)

WriteTo writes golden file to w.

type File added in v0.0.14

type File struct {
	Meta     map[string]interface{} `yaml:"meta,omitempty"`
	BodyType string                 `yaml:"bodyType"`
	Body     string                 `yaml:"body"`
	// contains filtered or unexported fields
}

File represents golden file with body and body type.

func New

func New(t T, r io.Reader) *File

New returns golden File representation.

func (*File) Assert added in v0.0.17

func (fil *File) Assert(data []byte)

Assert asserts file body matches data. It chooses the bast way to compare two byte slices based on body type. For example when comparing JSON both byte slices don't have to be identical but they must represent the same data.

func (*File) Bytes added in v0.0.17

func (fil *File) Bytes() []byte

Bytes returns body as byte slice.

func (*File) Unmarshal added in v0.3.0

func (fil *File) Unmarshal(v interface{})

Unmarshal unmarshalls file body to v based on BodyType. When body type is set to text v can be pointer to sting or byte slice (with enough space to fit body). Calls Fatal if body cannot be unmarshalled.

func (*File) WriteTo added in v0.0.17

func (fil *File) WriteTo(w io.Writer) (int64, error)

WriteTo writes golden file to w.

type Map added in v0.0.7

type Map map[string]interface{}

Map is a helper type for constructing template data.

func (Map) Add added in v0.0.7

func (m Map) Add(key string, val interface{}) Map

Add adds key and val to map and returns map for chaining.

type Request added in v0.0.2

type Request struct {
	Scheme   string                 `yaml:"scheme"`
	Method   string                 `yaml:"method"`
	Path     string                 `yaml:"path"`
	Query    string                 `yaml:"query"`
	Headers  []string               `yaml:"headers"`
	BodyType string                 `yaml:"bodyType"`
	Body     string                 `yaml:"body"`
	Meta     map[string]interface{} `yaml:"meta,omitempty"`
	// contains filtered or unexported fields
}

Request represents golden file for HTTP request.

func NewRequest added in v0.0.2

func NewRequest(t T, r io.Reader) *Request

NewRequest returns new instance of Request.

func (*Request) Assert added in v0.0.8

func (req *Request) Assert(got *http.Request)

Assert asserts request matches the golden file.

All headers defined in the golden file must match exactly but passed request may have more headers than defined in the golden file.

To compare request bodies the method best for defined body type is used. For example when comparing JSON bodies both byte slices don't have to be identical, but they must represent the same data.

func (*Request) BindQuery added in v0.0.13

func (req *Request) BindQuery(tag string, v interface{})

BindQuery binds request query parameters to v.

func (*Request) Bytes added in v0.0.16

func (req *Request) Bytes() []byte

Bytes returns request body as byte slice.

func (*Request) Request added in v0.0.2

func (req *Request) Request() *http.Request

Request returns HTTP request represented by the golden file. It panics on error.

func (*Request) Unmarshal added in v0.3.0

func (req *Request) Unmarshal(v interface{})

Unmarshal unmarshalls request body to v based on body type. When body type is set to text v can be pointer to sting or byte slice (with enough space to fit body). Calls Fatal if body cannot be unmarshalled.

type Response added in v0.0.6

type Response struct {
	StatusCode int                    `yaml:"statusCode"`
	Headers    []string               `yaml:"headers"`
	BodyType   string                 `yaml:"bodyType"`
	Body       string                 `yaml:"body"`
	Meta       map[string]interface{} `yaml:"meta,omitempty"`
	// contains filtered or unexported fields
}

Response represents golden file for HTTP response.

func NewResponse added in v0.2.0

func NewResponse(t T, r io.Reader) *Response

NewResponse returns new instance of Response.

func (*Response) Assert added in v0.0.8

func (rsp *Response) Assert(got *http.Response)

Assert asserts response matches the golden file.

All headers defined in the golden file must match exactly but passed response may have more headers then defined in the golden file.

To compare response bodies a method best suited for body type is used. For example when comparing JSON bodies both byte slices don't have to be identical but they must represent the same data.

func (*Response) Bytes added in v0.0.16

func (rsp *Response) Bytes() []byte

Bytes returns request body as byte slice.

func (*Response) Unmarshal added in v0.3.0

func (rsp *Response) Unmarshal(v interface{})

Unmarshal unmarshalls response body to v based on BodyType. Calls Fatal if body cannot be unmarshalled. Currently only JSON body type is supported.

type T added in v0.0.2

type T interface {
	// Fatal is equivalent to Log followed by FailNow.
	Fatal(args ...interface{})

	// Fatalf is equivalent to Logf followed by FailNow.
	Fatalf(format string, args ...interface{})

	// Helper marks the calling function as a test helper function.
	// When printing file and line information, that function will be skipped.
	// Helper may be called simultaneously from multiple goroutines.
	Helper()
}

T is a subset of testing.TB interface. It's primarily used to test golden package but can be used to implement custom actions to be taken on errors.

func Open added in v0.0.2

func Open(t T, pth string, data interface{}, opts ...tplOpt) (T, io.Reader)

Open reads golden file pointed by pth and returns it as a byte slice.

If data is not nil the golden file pointed by pth is treated as a template and applies a parsed template to the specified data object.

You can set template action delimiters using TplDelims function:

Open(t, "golden.yml", data, TplDelims("[[", "]]"))

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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