Categorygithub.com/hydronica/trial
modulepackage
0.7.2
Repository: https://github.com/hydronica/trial.git
Documentation: pkg.go.dev

# 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

ExamplesCompare FunctionsHelper 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

# Functions

AllowAllUnexported sets cmp.Diff to allow all unexported (private) variables.
ApproxTime is a wrapper around the cmpopts.EquateApproxTime it will consider time.Time values equal if there difference is less than the defined duration.
Args converts any number of parameters to an interface.
BoolP returns a pointer to a defined bool.
CaptureLog overrides the log output for reading.
CaptureStdErr redirects stderr for reading note this does not redirect log output.
CaptureStdOut redirects stdout for reading.
CmpFuncs tries to determine if x is the same function as y.
Contains determines if y is a subset of x.
Equal use the cmp.Diff method to check equality and display differences.
EqualOpt allow easy customization of the cmp.Equal method.
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.
ErrType can be used with ExpectedErr to check that the expected err is of a certain type.
Float32P returns a pointer to a defined float32.
Float64P returns a pointer to a defined float64.
IgnoreAllUnexported sets cmp.Diff to ignore all unexported (private) variables.
IgnoreFields is a wrapper around the cmpopts.IgnoreFields syntax: IgnoreFields(package.struct.Field).
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.
Int16P returns a pointer to a defined int16.
Int32P returns a pointer to a defined int32.
Int64P returns a pointer to a defined int64.
Int8P returns a pointer to a defined int8.
IntP returns a pointer to a defined int.
No description provided by the author
StringP returns a pointer to a defined string.
Time is a panic wrapper for the time.Parse method it returns a time.Time for the given layout and value.
TimeDay is a helper method for parsing times with day precision.
TimeHour is a helper method for parsing times with hour precision.
TimeP return a pointers to a time.Time for the given layout and value.
Times is a panic wrapper for the time.Parse method it returns a time.Time slice for the given layout and values.
Uint16P returns a pointer to a defined uint16.
Uint32P returns a pointer to a defined uint32.
Uint64P returns a pointer to a defined uint64.
Uint8P returns a pointer to a defined uint8.
UintP returns a pointer to a defined uint.

# Constants

No description provided by the author
No description provided by the author
No description provided by the author

# Structs

Case made during the trial of your code.
Input the input value given to the trial test function.
Trial framework used to test different logical states.

# Interfaces

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

# Type aliases

Cases made during the trial.
No description provided by the author
No description provided by the author