golden

package module
Version: v0.7.1 Latest Latest
Warning

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

Go to latest
Published: Mar 29, 2021 License: BSD-3-Clause Imports: 10 Imported by: 0

README

Golden

codecov Go Report Card GoDoc

Package golden testing with golden files in Go. A golden file is the expected output of test, stored as a separate file rather than as a string literal inside the test code. So when the test is executed, it will read data from the file and compare it to the output produced by the functionality under test.

When writing unit tests, there comes a point when you need to check that the complex output of a function matches your expectations. This could be binary data (like an Image, JSON, HTML etc). Golden files are a way of ensuring your function output matches its .golden file. It’s a pattern used in the Go standard library.

One of the advantages of the gold files approach is that you can easily update the test data using the command line flag without copying the data into the text variables of go this is very convenient in case of significant changes in the behavior of the system but also requires attention to the changed test data and checking the correctness of the new golden results.

A special cli is provided in the package. The special flag -update is provided in the package for conveniently updating ethos files, for example, using the following command:

go test ./... -update

Golden files are placed in directory testdata this directory is ignored by the standard tools go, and it can accommodate a variety of data used in test or samples.

Installation

go get github.com/xorcare/golden

Examples

Inspiration

License

© Vasiliy Vasilyuk, 2019-2021

Released under the BSD 3-Clause License.

Documentation

Overview

Package golden testing with golden files in Go. A golden file is the expected output of test, stored as a separate file rather than as a string literal inside the test code. So when the test is executed, it will read data from the file and compare it to the output produced by the functionality under test.

When writing unit tests, there comes a point when you need to check that the complex output of a function matches your expectations. This could be binary data (like an Image, JSON, HTML etc). Golden files are a way of ensuring your function output matches its .golden file. It’s a pattern used in the Go standard library.

One of the advantages of the gold files approach is that you can easily update the test data using the command line flag without copying the data into the text variables of go this is very convenient in case of significant changes in the behavior of the system but also requires attention to the changed test data and checking the correctness of the new golden results.

A special cli is provided in the package. The special flag `-update` is provided in the package for conveniently updating ethos files, for example, using the following command:

go test ./... -update

Golden files are placed in directory `testdata` this directory is ignored by the standard tools go, and it can accommodate a variety of data used in test or samples.

Index

Examples

Constants

View Source
const (
	// Golden file target.
	Golden target = iota
	// Input file target.
	Input
)

Variables

This section is empty.

Functions

func Assert

func Assert(t TestingTB, got []byte)

Assert is a tool to compare the actual value obtained in the test and the value from the golden file. Also, built-in functionality for updating golden files using the command line flag.

Example

In the current example, the value of `got` will be compared with the value of `want` that we get from the file `testdata/ExampleAssert.golden` and after comparing the data if there is a difference, the test will be aborted with an error. If you run the test flag is used with the `-update` data from the variable `got` is written in the golden file.

The test name is assumed to be equal to ExampleAssert.

package main

import (
	"encoding/base64"
	"fmt"
	"path"
	"regexp"
	"runtime"
	"strings"
	"unicode"

	"github.com/stretchr/testify/assert"
	"github.com/xorcare/golden"
)

func main() {
	t := newTestingT()

	got, err := base64.RawURLEncoding.DecodeString("Z29sZGVu")
	assert.NoError(t, err)

	golden.Assert(t, got)

}

type T struct {
	name string
}

func (t *T) Fail()    {}
func (t *T) FailNow() {}
func (t *T) Helper()  {}

func (t T) Name() string { return t.name }

func (t *T) Errorf(format string, args ...interface{}) { t.Logf(format, args...) }
func (t *T) Fatalf(format string, args ...interface{}) { t.Logf(format, args...) }

func (t *T) Logf(format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)

	re := regexp.MustCompile(`(?im)Error Trace:([\w\s:.]+)Error:`)
	msg = re.ReplaceAllString(msg, "Error Trace:\n\tError:")

	msg = strings.Replace(msg, "\t", "", -1)

	re = regexp.MustCompile(`(?im)^(.*)$`)
	msg = re.ReplaceAllStringFunc(msg, func(s string) string {
		return strings.TrimRightFunc(s, unicode.IsSpace)
	})

	fmt.Println(msg)
}

func newTestingT() *T {
	t := T{name: "TestExamples"}
	t.name = path.Join(t.name, caller(2))
	return &t
}

func caller(skip int) string {
	pc, _, _, ok := runtime.Caller(skip)
	if !ok {
		panic(fmt.Sprintf("Couldn't get the caller info level: %d", skip))
	}

	fp := runtime.FuncForPC(pc).Name()
	parts := strings.Split(fp, ".")
	fn := parts[len(parts)-1]

	return fn
}
Output:

golden: read the value of nil since it is not found file: testdata/TestExamples/ExampleAssert.golden

Error Trace:
Error:      Not equal:
            expected: "[]byte(nil)"
            actual  : "golden"

            Diff:
            --- Expected
            +++ Actual
            @@ -1 +1 @@
            -[]byte(nil)
            +golden

func Read

func Read(t TestingTB) []byte

Read is a functional for reading both input and golden files using the appropriate target.

Example

ExampleRead the example shows how you can use the global api to read files together with the already considered golden.Assert.

The test name is assumed to be equal to ExampleRead.

package main

import (
	"encoding/base64"
	"fmt"
	"path"
	"regexp"
	"runtime"
	"strings"
	"unicode"

	"github.com/stretchr/testify/assert"
	"github.com/xorcare/golden"
)

func main() {
	t := newTestingT()

	input := string(golden.Read(t))
	got, err := base64.RawURLEncoding.DecodeString(input)
	assert.NoError(t, err)

	golden.Assert(t, got)

}

type T struct {
	name string
}

func (t *T) Fail()    {}
func (t *T) FailNow() {}
func (t *T) Helper()  {}

func (t T) Name() string { return t.name }

func (t *T) Errorf(format string, args ...interface{}) { t.Logf(format, args...) }
func (t *T) Fatalf(format string, args ...interface{}) { t.Logf(format, args...) }

func (t *T) Logf(format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)

	re := regexp.MustCompile(`(?im)Error Trace:([\w\s:.]+)Error:`)
	msg = re.ReplaceAllString(msg, "Error Trace:\n\tError:")

	msg = strings.Replace(msg, "\t", "", -1)

	re = regexp.MustCompile(`(?im)^(.*)$`)
	msg = re.ReplaceAllStringFunc(msg, func(s string) string {
		return strings.TrimRightFunc(s, unicode.IsSpace)
	})

	fmt.Println(msg)
}

func newTestingT() *T {
	t := T{name: "TestExamples"}
	t.name = path.Join(t.name, caller(2))
	return &t
}

func caller(skip int) string {
	pc, _, _, ok := runtime.Caller(skip)
	if !ok {
		panic(fmt.Sprintf("Couldn't get the caller info level: %d", skip))
	}

	fp := runtime.FuncForPC(pc).Name()
	parts := strings.Split(fp, ".")
	fn := parts[len(parts)-1]

	return fn
}
Output:

golden: read the value of nil since it is not found file: testdata/TestExamples/ExampleRead.input
golden: read the value of nil since it is not found file: testdata/TestExamples/ExampleRead.golden

Error Trace:
Error:      Not equal:
            expected: "[]byte(nil)"
            actual  : ""

            Diff:
            --- Expected
            +++ Actual
            @@ -1 +1 @@
            -[]byte(nil)
            +

func Run

func Run(t TestingTB, do func(input []byte) (outcome []byte, err error))

Run is a functional that automates the process of reading the input file of the test bytes and the execution of the input function of testing and checking the results.

Example

In the current example, when you run the Run function, the data from the `testdata/ExampleRun.input` file will be read and with this data will be called the function, which is passed in, as a result of the function execution we will get the `got` data and possibly an error, which will be processed by the internal method implementation. The `got` will be compared with the meaning `want` which we get from the file `test data/ExampleRun.golden` and after data comparison in case of differences, the test will be fail. If you run the test flag is used with the `-update` data from the variable `got` is written in the golden file.

The test name is assumed to be equal to ExampleRun.

package main

import (
	"encoding/base64"
	"fmt"
	"path"
	"regexp"
	"runtime"
	"strings"
	"unicode"

	"github.com/xorcare/golden"
)

func main() {
	t := newTestingT()

	golden.Run(t, func(input []byte) (got []byte, err error) {
		return base64.RawURLEncoding.DecodeString(string(input))
	})
}

type T struct {
	name string
}

func (t *T) Fail()    {}
func (t *T) FailNow() {}
func (t *T) Helper()  {}

func (t T) Name() string { return t.name }

func (t *T) Errorf(format string, args ...interface{}) { t.Logf(format, args...) }
func (t *T) Fatalf(format string, args ...interface{}) { t.Logf(format, args...) }

func (t *T) Logf(format string, args ...interface{}) {
	msg := fmt.Sprintf(format, args...)

	re := regexp.MustCompile(`(?im)Error Trace:([\w\s:.]+)Error:`)
	msg = re.ReplaceAllString(msg, "Error Trace:\n\tError:")

	msg = strings.Replace(msg, "\t", "", -1)

	re = regexp.MustCompile(`(?im)^(.*)$`)
	msg = re.ReplaceAllStringFunc(msg, func(s string) string {
		return strings.TrimRightFunc(s, unicode.IsSpace)
	})

	fmt.Println(msg)
}

func newTestingT() *T {
	t := T{name: "TestExamples"}
	t.name = path.Join(t.name, caller(2))
	return &t
}

func caller(skip int) string {
	pc, _, _, ok := runtime.Caller(skip)
	if !ok {
		panic(fmt.Sprintf("Couldn't get the caller info level: %d", skip))
	}

	fp := runtime.FuncForPC(pc).Name()
	parts := strings.Split(fp, ".")
	fn := parts[len(parts)-1]

	return fn
}
Output:

golden: read the value of nil since it is not found file: testdata/TestExamples/ExampleRun.input
golden: read the value of nil since it is not found file: testdata/TestExamples/ExampleRun.golden

Error Trace:
Error:      Not equal:
            expected: "[]byte(nil)"
            actual  : ""

            Diff:
            --- Expected
            +++ Actual
            @@ -1 +1 @@
            -[]byte(nil)
            +

Types

type Conclusion added in v0.5.0

type Conclusion interface {
	// Failed reports whether the function has failed.
	Failed() bool
	// Fail marks the function as having failed but continues execution.
	// Also accompanying messages will be printed in the output of the test.
	// ATTENTION! executed only if expression is false `Failed() == true`.
	Fail()
	// FailNow marks the function as having failed and stops its execution
	// by calling runtime.Goexit (which then runs all deferred calls in the
	// current goroutine).
	// ATTENTION! executed only if expression is false `Failed() == true`.
	FailNow()
}

Conclusion interface wrapping conclusion.

func Equal added in v0.5.0

func Equal(t TestingTB, got []byte) Conclusion

Equal is a tool to compare the actual value obtained in the test and the value from the golden file. Also, built-in functionality for updating golden files using the command line flag.

func JSONEq added in v0.6.0

func JSONEq(tb TestingTB, got string) Conclusion

JSONEq is a tool to compare the actual JSON value obtained in the test and the value from the golden file. Also, built-in functionality for updating golden files using the command line flag.

type TestingTB added in v0.4.1

type TestingTB interface {
	Name() string
	Logf(format string, args ...interface{})
	Errorf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})
	FailNow()
	Fail()
}

TestingTB is the interface common to T and B.

type Tool

type Tool struct {
	// contains filtered or unexported fields
}

Tool implements the basic logic of working with golden files. All functionality is implemented through a non-mutating state machine, which at a certain point in time can perform an action on the basis of the state or change any parameter by creating a new copy of the state.

func SetTest

func SetTest(t TestingTB) Tool

SetTest is a mechanism to create a new copy of the base Tool object for advanced use. This method replaces the constructor for the Tool structure.

func SetWant added in v0.7.0

func SetWant(t TestingTB, bs []byte) Tool

SetWant a place to set the expected want manually. want value it stores manually set expected data, if it is nil, then the data will be read from the files, otherwise the value from this field will be taken.

func (Tool) Assert

func (t Tool) Assert(got []byte)

Assert is a tool to compare the actual value obtained in the test and the value from the golden file. Also, built-in functionality for updating golden files using the command line flag.

func (Tool) Equal added in v0.5.0

func (t Tool) Equal(got []byte) Conclusion

Equal is a tool to compare the actual value obtained in the test and the value from the golden file. Also, built-in functionality for updating golden files using the command line flag.

func (Tool) JSONEq added in v0.6.0

func (t Tool) JSONEq(got string) Conclusion

JSONEq is a tool to compare the actual JSON value obtained in the test and the value from the golden file. Also, built-in functionality for updating golden files using the command line flag.

func (Tool) Read

func (t Tool) Read() (bs []byte)

Read is a functional for reading both input and golden files using the appropriate target.

func (Tool) Run

func (t Tool) Run(do func(input []byte) (got []byte, err error))

Run is a functional that automates the process of reading the input file of the test bytes and the execution of the input function of testing and checking the results.

func (Tool) SetPrefix added in v0.3.0

func (t Tool) SetPrefix(prefix string) Tool

SetPrefix a prefix value setter.

func (Tool) SetTarget

func (t Tool) SetTarget(tar target) Tool

SetTarget a target value setter.

func (Tool) SetTest

func (t Tool) SetTest(tb TestingTB) Tool

SetTest a test value setter in the call chain must be used first to prevent abnormal situations when using other methods.

func (Tool) SetWant added in v0.7.0

func (t Tool) SetWant(bs []byte) Tool

SetWant a place to set the expected want manually. want value it stores manually set expected data, if it is nil, then the data will be read from the files, otherwise the value from this field will be taken.

func (Tool) Update

func (t Tool) Update(bs []byte)

Update functional reviewer is the need to update the golden files and doing it.

Directories

Path Synopsis
internal
integration
Package integration is needed to test the functionality of golden in integration with the file system.
Package integration is needed to test the functionality of golden in integration with the file system.

Jump to

Keyboard shortcuts

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