trial

package module
v0.7.2 Latest Latest
Warning

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

Go to latest
Published: Nov 28, 2023 License: MIT Imports: 14 Imported by: 0

README

Trial - Prove the Innocence of your code

GoDoc Build Status Go Report Card codecov

Go testing framework to make tests easier to create, maintain and debug.

See wiki for tips and guides

Examples Compare Functions Helper Functions

Philosophy

  • Table Driven Tests
  • Descriptive
    • tests should describe the expected behavior of a function
    • case needs unique description
    • easy to read and change
  • Fast - the test suite should run in under 5 minutes
  • Independent
    • Each case should be fully isolated
    • doesn't depend on previous cases running
    • order of cases shouldn't matter
  • Repeatable: non-flaky, runs regardless of the time of year
  • Test for observable behavior

Features

  • function verification.
    • Check results for exact matches including private values (default behavior)
    • Check results for values contained in others (see Contains function)
    • Allows for custom compare functions
  • Catch and test for panics
    • each test is self isolated so a panic won't stop other cases from running
    • check for expected panic cases with ShouldPanic
  • Test error cases
    • Check that a function returns an error: ShouldErr
    • Check that an error strings contains expected string: ExpectedErr
    • Check that an error is of expected type: ExpectedErr: ErrType(err)
  • Fail tests that take too long to complete
    • trial.New(fn,cases).Timeout(time.Second)

Getting Starting

go get github.com/hydronica/trial

Each test has 3 parts to it. A function to test against, a set of test cases to validate with and trial that sets up the table driven tests

Test Function
testFunc[In any, Out any] func(in In) (result Out, err error)

a generic function that has a single input and returns a result and an error. Wrap your function to test more complex functions or methods.

Example

  fn := func(i int) (string, error) {
    return strconv.ItoA(i), nil 
  }

Cases

a collection (map) of test cases that have a unique title and defined input to be passed to the test function. The expected behavior is described by providing an output, setting an ExpectedErr or saying it ShouldErr. ShouldPanic can be used to test when function panic condition.

type Case[In any, Out any] struct {
	Input    In
	Expected Out


	ShouldErr   bool  // is an error expected
	ExpectedErr error // the error that was expected (nil is no error expected)
	ShouldPanic bool  // is a panic expected
}

Each

  • Input generic - a convenience structure to handle input more dynamically
  • Expected generic - the expected output of the method being tested.
    • This is compared with the result from the TestFunc
  • ShouldErr bool - indicates the function should return an error
  • ExpectedErr error - verifies the function error string matches the result
    • uses strings.Contains to check
    • also implies that the method should error so setting ShouldErr to true is not required
    • use ErrType to test that the error is the same type as expected.
  • ShouldPanic bool - indicates the method should panic
Trial Setup

Run the test cases either within a single test function or as subtests. The input and output values must match between the test function and cases.

trial.New(fn,cases).Test(t)
// or 
trial.New(fn,cases).SubTest(t)

By default trial uses a strict matching values and uses cmp.Equal to compare values. Compare Functions can be customized to ignore certain fields or are contained withing maps, slices or strings. See Compare Functions for more details. A timeout can be added onto the trial builder with .Timeout(time.Second)

Getting Started Template
fn := func(in any) (any, error) {
    // TODO: setup test case, call routine and return result
    return nil, nil
}
cases := trail.Cases{
    "default": {
        Input:    123,
        Expected: 1,
    },
}
trial.New(fn,cases).Test(t)

For more examples see the wiki

Compare Functions

used to compare two values to determine equality and displayed a detailed string describing any differences.

func(actual, expected any) (equal bool, differences string)

override the default

trial.New(fn, cases).Comparer(myComparer).Test(t)

Equal

The default comparer used, it is a wrapping for cmp.Equal with the AllowUnexported option set for all structs. This causes all fields (public and private) in a struct to be compared. (see https://github.com/google/go-cmp)

EqualOpt

Customize the use of cmp.Equal with the following supported options:

  • AllowAllUnexported - [default: Equal] compare all unexported (private) variables within a struct. This is useful when testing a struct inside its own package.
  • IgnoreAllUnexported - ignore all unexported (private) variables within a struct. This is useful when dealing with a struct outside the project.
  • IgnoreFields(fields ...string) - define a list of variables to exclude for the comparer, the field name are case sensitize and can be dot-delimited ("Field", "Parent.child")
  • EquateEmpty- [default: Equal] a nil map or slice is equal to an empty one (len is zero)
  • IgnoreTypes(values ...interface{}) - ignore all types of the values passed in. Ex: IgnoreTypes(int64(0), float32(0.0)) ignore int64 and float32
  • ApproxTime(d time.Duration) - approximates time values to to the nearest duration.
// example struct that is compared to expected
type Example struct {
  Field1     int
  Field2     int
  ignoreMe   string     // ignored unexported
  Timestamp  time.Time  // ignored
  LastUpdate time.Time  // ignored
}

	trial.New(fn, cases).Comparer(
		trial.EqualOpt(
			trial.IgnoreAllUnexported,
			trial.IgnoreFields("Timestamp", "LastUpdate")),
	).SubTest(t)

Contains ⊇

Checks if the expected value is contained in the actual value. The symbol ⊇ is used to donate a subset. ∈ is used to show that a value exists in a slice. Contains checks the following relationships

  • string ⊇ string
    • is the expected string contained in the actual string (strings.Contains)
  • string ⊇ []string
    • are the expected substrings contained in the actual string
  • []interface{} ⊇ interface{}
    • is the expected value found in the slice or array
  • []interface{} ⊇ []interface{}
    • is the expected slice a subset of the actual slice. all values in expected exist and are contained in actual.
  • map[key]interface{} ⊇ map[key]interface{}
    • is the expected map a subset of the actual map. all keys in expected are in actual and all values under that key are contained in actual

Documentation

Index

Constants

View Source
const (
	SubStrings = iota
	SubSlices
	SubMaps
)

Variables

This section is empty.

Functions

func AllowAllUnexported added in v0.6.0

func AllowAllUnexported(i interface{}) cmp.Option

AllowAllUnexported sets cmp.Diff to allow all unexported (private) variables

func ApproxTime added in v0.6.0

func ApproxTime(d time.Duration) func(interface{}) cmp.Option

ApproxTime is a wrapper around the cmpopts.EquateApproxTime it will consider time.Time values equal if there difference is less than the defined duration

func BoolP added in v0.4.0

func BoolP(b bool) *bool

BoolP returns a pointer to a defined bool

func CaptureLog added in v0.4.0

func CaptureLog() *capture

CaptureLog overrides the log output for reading

func CaptureStdErr added in v0.4.0

func CaptureStdErr() *capture

CaptureStdErr redirects stderr for reading note this does not redirect log output

func CaptureStdOut added in v0.4.0

func CaptureStdOut() *capture

CaptureStdOut redirects stdout for reading

func CmpFuncs

func CmpFuncs(x, y interface{}) (b bool, s string)

CmpFuncs tries to determine if x is the same function as y.

func Contains added in v0.4.0

func Contains(x, y interface{}) (bool, string)

Contains determines if y is a subset of x. x is a string -> y is a string that is equal to or a subset of x (string.Contains) x is a slice or array -> y is contained in x x is a map -> y is a map and is contained in x

func Equal

func Equal(actual, expected interface{}) (bool, string)

Equal use the cmp.Diff method to check equality and display differences. This method checks all unexpected values

func EqualOpt added in v0.6.0

func EqualOpt(optFns ...func(i interface{}) cmp.Option) func(actual, expected interface{}) (bool, string)

EqualOpt allow easy customization of the cmp.Equal method. see below for a list of supported options

func EquateEmpty added in v0.6.0

func EquateEmpty(i interface{}) cmp.Option

EquateEmpty is a wrapper around cmpopts.EquateEmpty it determines all maps and slices with a length of zero to be equal, regardless of whether they are nil

func ErrType

func ErrType(err error) error

ErrType can be used with ExpectedErr to check that the expected err is of a certain type

func Float32P

func Float32P(f float32) *float32

Float32P returns a pointer to a defined float32

func Float64P

func Float64P(f float64) *float64

Float64P returns a pointer to a defined float64

func IgnoreAllUnexported added in v0.6.0

func IgnoreAllUnexported(i interface{}) cmp.Option

IgnoreAllUnexported sets cmp.Diff to ignore all unexported (private) variables

func IgnoreFields added in v0.6.0

func IgnoreFields(f ...string) func(interface{}) cmp.Option

IgnoreFields is a wrapper around the cmpopts.IgnoreFields syntax: IgnoreFields(package.struct.Field)

func IgnoreTypes added in v0.6.0

func IgnoreTypes(types ...interface{}) func(interface{}) cmp.Option

IgnoreTypes is a wrapper around the cmpopts.IgnoreTypes it allows ignore the type of the values passed in int32(0), int(0), string(0), time.Duration(0), etc

func Int16P

func Int16P(i int16) *int16

Int16P returns a pointer to a defined int16

func Int32P

func Int32P(i int32) *int32

Int32P returns a pointer to a defined int32

func Int64P

func Int64P(i int64) *int64

Int64P returns a pointer to a defined int64

func Int8P

func Int8P(i int8) *int8

Int8P returns a pointer to a defined int8

func IntP

func IntP(i int) *int

IntP returns a pointer to a defined int

func StringP added in v0.4.0

func StringP(s string) *string

StringP returns a pointer to a defined string

func Time

func Time(layout, value string) time.Time

Time is a panic wrapper for the time.Parse method it returns a time.Time for the given layout and value

func TimeDay

func TimeDay(value string) time.Time

TimeDay is a helper method for parsing times with day precision. format 2006-01-02

func TimeHour

func TimeHour(value string) time.Time

TimeHour is a helper method for parsing times with hour precision. format 2006-01-02T15

func TimeP

func TimeP(layout, value string) *time.Time

TimeP return a pointers to a time.Time for the given layout and value. it panics on error

func Times

func Times(layout string, values ...string) []time.Time

Times is a panic wrapper for the time.Parse method it returns a time.Time slice for the given layout and values

func Uint16P added in v0.4.0

func Uint16P(i uint16) *uint16

Uint16P returns a pointer to a defined uint16

func Uint32P added in v0.4.0

func Uint32P(i uint32) *uint32

Uint32P returns a pointer to a defined uint32

func Uint64P added in v0.4.0

func Uint64P(i uint64) *uint64

Uint64P returns a pointer to a defined uint64

func Uint8P added in v0.4.0

func Uint8P(i uint8) *uint8

Uint8P returns a pointer to a defined uint8

func UintP added in v0.4.0

func UintP(i uint) *uint

UintP returns a pointer to a defined uint

Types

type Case

type Case[In any, Out any] struct {
	Input    In
	Expected Out

	// testing conditions
	ShouldErr   bool  // is an error expected
	ExpectedErr error // the error that was expected (nil is no error expected)
	ShouldPanic bool  // is a panic expected
}

Case made during the trial of your code

type Cases

type Cases[In any, Out any] map[string]Case[In, Out]

Cases made during the trial

type CompareFunc added in v0.4.0

type CompareFunc func(actual, expected interface{}) (equal bool, differences string)

CompareFunc compares actual and expected to determine equality. It should return a human readable string representing the differences between actual and expected. Symbols with meaning: "-" elements missing from actual "+" elements missing from expected

type Comparer added in v0.4.0

type Comparer interface {
	Equals(interface{}) (bool, string)
}

Comparer interface is implemented by an object to check for equality and show any differences found

type Input added in v0.4.0

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

Input the input value given to the trial test function

func Args

func Args(args ...interface{}) Input

Args converts any number of parameters to an interface. generally used with Case's Input for multiple params

func (Input) Bool added in v0.4.0

func (in Input) Bool() bool

Bool value of input, panics on non bool value

func (Input) Float64 added in v0.4.0

func (in Input) Float64() float64

Float64 value of input, panics on non float64 value

func (Input) Int added in v0.4.0

func (in Input) Int() int

Int value of input, panics on non int value

func (Input) Interface added in v0.4.0

func (in Input) Interface() interface{}

Interface returns the current value of input

func (Input) Map added in v0.4.0

func (in Input) Map(key interface{}) Input

Map returns the value for the provided key, panics on non map value

func (Input) Slice added in v0.4.0

func (in Input) Slice(i int) Input

Slice returns the input value of the index of a slice/array. panics if non slice value

func (Input) String added in v0.4.0

func (in Input) String() string

String value of input, panics on on non string value

func (Input) Uint added in v0.4.0

func (in Input) Uint() uint

Uint value of input, panics on non uint value

type TestFunc

type TestFunc func(in Input) (result interface{}, err error)

TestFunc a wrapper function used to setup the method being tested.

type Trial

type Trial[In any, Out any] struct {
	// contains filtered or unexported fields
}

Trial framework used to test different logical states

func New

func New[In any, Out any](fn func(In) (Out, error), cases map[string]Case[In, Out]) *Trial[In, Out]

func (*Trial[In, Out]) Comparer added in v0.4.0

func (t *Trial[In, Out]) Comparer(fn CompareFunc) *Trial[In, Out]

Comparer override the default comparison function. see Contains(x, y interface{}) (bool, string) see Equals(x, y interface{}) (bool, string)

func (*Trial[In, Out]) EqualFn

func (t *Trial[In, Out]) EqualFn(fn CompareFunc) *Trial[In, Out]

EqualFn override the default comparison method used. see ContainsFn(x, y interface{}) (bool, string) deprecated

func (*Trial[In, Out]) SubTest added in v0.4.0

func (t *Trial[In, Out]) SubTest(tst testing.TB)

SubTest runs all cases as individual subtests

func (*Trial[In, Out]) Test

func (t *Trial[In, Out]) Test(tst testing.TB)

Test all cases provided

func (*Trial[In, Out]) Timeout added in v0.5.0

func (t *Trial[In, Out]) Timeout(d time.Duration) *Trial[In, Out]

Timeout will make sure that a test case has finished within the timeout or the test will fail.

Jump to

Keyboard shortcuts

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