Documentation
¶
Overview ¶
Package check provide helpers to complement Go testing package.
Features ¶
This package is like testify/assert on steroids. :)
- Compelling output from failed tests:
- Very easy-to-read dumps for expected and actual values.
- Same text diff you loved in testify/assert.
- Also visual diff in GoConvey web UI, if you use it (recommended).
- Statistics with amount of passed/failed checks.
- Colored output in terminal.
- 100% compatible with testing package - check package just provide convenient wrappers for *testing.T methods and doesn't introduce new concepts like BDD, custom test suite or unusual execution flow.
- All checks you may ever need! :)
- Very easy to add your own check functions.
- Concise, handy and consistent API, without dot-import!
Quickstart ¶
Just wrap each (including subtests) *testing.T in check.T and write tests as usually with testing package. Call new methods provided by this package to have more clean/concise test code and cool dump/diff.
import "github.com/powerman/check"
func TestSomething(tt *testing.T) {
t := check.T{tt}
t.Equal(2, 2)
t.Log("You can use new t just like usual *testing.T")
t.Run("Subtests/Parallel example", func(tt *testing.T) {
t := check.T{tt}
t.Parallel()
t.NotEqual(2, 3, "should not be 3!")
obj, err := NewObj()
if t.Nil(err) {
t.Match(obj.field, `^\d+$`)
}
})
}
To get optional statistics about executed checkers add:
func TestMain(m *testing.M) { check.TestMain(m) }
When use goconvey tool, to get nice diff in web UI add:
import _ "github.com/smartystreets/goconvey/convey"
Hints ¶
★ How to check for errors:
// If you just want nil:
t.Nil(err)
t.Err(err, nil)
// Check for (absence of) concrete error:
t.Err(err, io.EOF)
t.NotErr(err, io.EOF) // nil is not io.EOF, so it's ok too
// When need to match by error's text:
t.Match(err, "file.*permission")
// Use Equal ONLY when checking for same instance:
t.Equal(io.EOF, io.EOF) // this works
t.Equal(io.EOF, errors.New("EOF")) // this doesn't work!
t.Err(io.EOF, errors.New("EOF")) // this works
t.DeepEqual(io.EOF, errors.New("EOF")) // this works too
★ Each check returns bool, so you can easily skip problematic code:
if t.Nil(err) {
t.Match(obj.field, `^\d+$`)
}
★ You can turn any check into assertion to stop test immediately:
t.Must(t.Nil(err))
★ You can provide extra description to each check:
t.Equal(got, want, "Just msg: will Print(), % isn't special") t.Equal(got, want, "Msg with args: will Printf(): %v", extra)
★ There are short synonyms for checks implementing usual ==, !=, etc.:
t.EQ(got, want) // same as t.Equal t.NE(got, want) // same as t.NotEqual t.LT(got, want) // same as t.Less t.LE(got, want) // same as t.LessOrEqual t.GT(got, want) // same as t.Greater t.GE(got, want) // same as t.GreaterOrEqual
★ If you need custom check, which isn't available out-of-box - see Should checker, it'll let you plug in your own checker with ease.
★ It will panic when called with arg of wrong type - because this means bug in your test.
Contents ¶
There are few special functions (assertions and custom checkers).
Must Should
Everything else are just trivial (mostly) checkers which works in obvious way and accept values of any types which makes sense (and panics on everything else).
Nil NotNil Zero NotZero True False Equal NotEqual EQ NE DeepEqual NotDeepEqual Err NotErr BytesEqual NotBytesEqual JSONEqual Greater LessOrEqual GT LE Less GreaterOrEqual LT GE Between NotBetween BetweenOrEqual NotBetweenOrEqual InDelta NotInDelta InSMAPE NotInSMAPE Len NotLen Match NotMatch HasPrefix NotHasPrefix HasSuffix NotHasSuffix HasKey NotHasKey Contains NotContains HasType NotHasType Implements NotImplements Panic NotPanic PanicMatch PanicNotMatch
Index ¶
- func Report()
- func TestMain(m *testing.M)
- type ShouldFunc1
- type ShouldFunc2
- type T
- func (t *T) Between(actual, min, max interface{}, msg ...interface{}) bool
- func (t *T) BetweenOrEqual(actual, min, max interface{}, msg ...interface{}) bool
- func (t *T) BytesEqual(actual, expected []byte, msg ...interface{}) bool
- func (t *T) Contains(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) DeepEqual(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) EQ(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) Equal(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) Err(actual, expected error, msg ...interface{}) bool
- func (t *T) False(cond bool, msg ...interface{}) bool
- func (t *T) GE(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) GT(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) Greater(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) GreaterOrEqual(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) HasKey(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) HasPrefix(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) HasSuffix(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) HasType(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) Implements(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) InDelta(actual, expected, delta interface{}, msg ...interface{}) bool
- func (t *T) InSMAPE(actual, expected interface{}, smape float64, msg ...interface{}) bool
- func (t *T) JSONEqual(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) LE(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) LT(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) Len(actual interface{}, expected int, msg ...interface{}) bool
- func (t *T) Less(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) LessOrEqual(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) Match(actual, regex interface{}, msg ...interface{}) bool
- func (t *T) Must(continueTest bool)
- func (t *T) NE(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) Nil(actual interface{}, msg ...interface{}) bool
- func (t *T) NotBetween(actual, min, max interface{}, msg ...interface{}) bool
- func (t *T) NotBetweenOrEqual(actual, min, max interface{}, msg ...interface{}) bool
- func (t *T) NotBytesEqual(actual, expected []byte, msg ...interface{}) bool
- func (t *T) NotContains(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) NotDeepEqual(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) NotEqual(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) NotErr(actual, expected error, msg ...interface{}) bool
- func (t *T) NotHasKey(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) NotHasPrefix(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) NotHasSuffix(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) NotHasType(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) NotImplements(actual, expected interface{}, msg ...interface{}) bool
- func (t *T) NotInDelta(actual, expected, delta interface{}, msg ...interface{}) bool
- func (t *T) NotInSMAPE(actual, expected interface{}, smape float64, msg ...interface{}) bool
- func (t *T) NotLen(actual interface{}, expected int, msg ...interface{}) bool
- func (t *T) NotMatch(actual, regex interface{}, msg ...interface{}) bool
- func (t *T) NotNil(actual interface{}, msg ...interface{}) bool
- func (t *T) NotPanic(actual func(), msg ...interface{}) bool
- func (t *T) NotZero(actual interface{}, msg ...interface{}) bool
- func (t *T) Panic(actual func(), msg ...interface{}) bool
- func (t *T) PanicMatch(actual func(), regex interface{}, msg ...interface{}) bool
- func (t *T) PanicNotMatch(actual func(), regex interface{}, msg ...interface{}) bool
- func (t *T) Parallel()
- func (t *T) Should(anyShouldFunc interface{}, args ...interface{}) bool
- func (t *T) True(cond bool, msg ...interface{}) bool
- func (t *T) Zero(actual interface{}, msg ...interface{}) bool
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type ShouldFunc1 ¶
ShouldFunc1 is like Nil or Zero.
type ShouldFunc2 ¶
ShouldFunc2 is like Equal or Match.
type T ¶
T wraps *testing.T to make it convenient to call checkers in test.
It's convenient to rename Test function's arg from t to something else, create wrapped variable with usual name t and use only t:
func TestSomething(tt *testing.T) {
t := check.T{tt}
// use only t in test and don't touch tt anymore
}
func (*T) Between ¶
Between checks for min < actual < max.
All three actual, min and max must be either:
- signed integers
- unsigned integers
- floats
- strings
- time.Time
func (*T) BetweenOrEqual ¶
BetweenOrEqual checks for min <= actual <= max.
All three actual, min and max must be either:
- signed integers
- unsigned integers
- floats
- strings
- time.Time
func (*T) BytesEqual ¶
BytesEqual checks for bytes.Equal(actual, expected).
Hint: BytesEqual([]byte{}, []byte(nil)) is true (unlike DeepEqual).
func (*T) Contains ¶
Contains checks is actual contains substring/element expected.
Element of array/slice/map is checked using == expected.
Type of expected depends on type of actual:
- if actual is a string, then expected should be a string
- if actual is an array, then expected should have array's element type
- if actual is a slice, then expected should have slice's element type
- if actual is a map, then expected should have map's value type
Hint: In a map it looks for a value, if you need to look for a key - use HasKey instead.
func (*T) Equal ¶
Equal checks for actual == expected.
Note: For time.Time it uses actual.Equal(expected) instead.
func (*T) Err ¶
Err checks is actual error is the same as expected error.
They may be a different instances, but must have same type and value.
Checking for nil is okay, but using Nil(actual) instead is more clean.
func (*T) Greater ¶
Greater checks for actual > expected.
Both actual and expected must be either:
- signed integers
- unsigned integers
- floats
- strings
- time.Time
func (*T) GreaterOrEqual ¶
GreaterOrEqual checks for actual >= expected.
Both actual and expected must be either:
- signed integers
- unsigned integers
- floats
- strings
- time.Time
func (*T) HasPrefix ¶
HasPrefix checks for strings.HasPrefix(actual, expected).
Both actual and expected may have any of these types:
- string - will use as is
- []byte - will convert with string()
- []rune - will convert with string()
- fmt.Stringer - will convert with actual.String()
- error - will convert with actual.Error()
- nil - check will always fail
func (*T) HasSuffix ¶
HasSuffix checks for strings.HasSuffix(actual, expected).
Both actual and expected may have any of these types:
- string - will use as is
- []byte - will convert with string()
- []rune - will convert with string()
- fmt.Stringer - will convert with actual.String()
- error - will convert with actual.Error()
- nil - check will always fail
func (*T) Implements ¶
Implements checks is actual implements interface pointed by expected.
You must use pointer to interface type in expected:
t.Implements(os.Stdin, (*io.Reader)(nil))
func (*T) InDelta ¶
InDelta checks for expected-delta <= actual <= expected+delta.
All three actual, expected and delta must be either:
- signed integers
- unsigned integers
- floats
- time.Time (in this case delta must be time.Duration)
func (*T) InSMAPE ¶
InSMAPE checks that actual and expected have a symmetric mean absolute percentage error (SMAPE) is less than given smape.
Both actual and expected must be either:
- signed integers
- unsigned integers
- floats
Allowed smape values are: 0.0 < smape < 100.0.
Used formula returns SMAPE value between 0 and 100 (percents):
- 0.0 when actual == expected
- ~0.5 when they differs in ~1%
- ~5 when they differs in ~10%
- ~20 when they differs in 1.5 times
- ~33 when they differs in 2 times
- 50.0 when they differs in 3 times
- ~82 when they differs in 10 times
- 99.0+ when actual and expected differs in 200+ times
- 100.0 when only one of actual or expected is 0 or one of them is positive while another is negative
func (*T) JSONEqual ¶
JSONEqual normalize formatting of actual and expected (if they're valid JSON) and then checks for bytes.Equal(actual, expected).
Both actual and expected may have any of these types:
- string
- []byte
- json.RawMessage
- *json.RawMessage
- nil
In case any of actual or expected is nil, "" or (for string, []byte or []rune) is invalid JSON - check will fail.
func (*T) Less ¶
Less checks for actual < expected.
Both actual and expected must be either:
- signed integers
- unsigned integers
- floats
- strings
- time.Time
func (*T) LessOrEqual ¶
LessOrEqual checks for actual <= expected.
Both actual and expected must be either:
- signed integers
- unsigned integers
- floats
- strings
- time.Time
func (*T) Match ¶
Match checks for regex.MatchString(actual).
Regex type can be either *regexp.Regexp or string.
Actual type can be:
- string - will match with actual
- []byte - will match with string(actual)
- []rune - will match with string(actual)
- fmt.Stringer - will match with actual.String()
- error - will match with actual.Error()
- nil - will not match (even with empty regex)
func (*T) Must ¶
Must interrupt test using t.FailNow if called with false value.
This provides easy way to turn any check into assertion:
t.Must(t.Nil(err))
func (*T) Nil ¶
Nil checks for actual == nil.
There is one subtle difference between this check and Go `== nil` (if this surprises you then you should read https://golang.org/doc/faq#nil_error first):
var intPtr *int
var empty interface{}
var notEmpty interface{} = intPtr
t.True(intPtr == nil) // TRUE
t.True(empty == nil) // TRUE
t.True(notEmpty == nil) // FALSE
When you call this function your actual value will be stored in interface{} argument, and this makes any typed nil pointer value `!= nil` inside this function (just like in example above happens with notEmpty variable).
As it is very common case to check some typed pointer using Nil this check has to work around and detect nil even if usual `== nil` return false. But this has nasty side effect: if actual value already was of interface type and contains some typed nil pointer (which is usually bad thing and should be avoid) then Nil check will pass (which may be not what you want/expect):
t.Nil(nil) // TRUE t.Nil(intPtr) // TRUE t.Nil(empty) // TRUE t.Nil(notEmpty) // WARNING: also TRUE!
Second subtle case is less usual: uintptr(0) is sorta nil, but not really, so Nil(uintptr(0)) will fail. Nil(unsafe.Pointer(nil)) will also fail, for the same reason. Please do not use this and consider this behaviour undefined, because it may change in the future.
func (*T) NotBetween ¶
NotBetween checks for actual <= min or max <= actual.
All three actual, min and max must be either:
- signed integers
- unsigned integers
- floats
- strings
- time.Time
func (*T) NotBetweenOrEqual ¶
NotBetweenOrEqual checks for actual < min or max < actual.
All three actual, min and max must be either:
- signed integers
- unsigned integers
- floats
- strings
- time.Time
func (*T) NotBytesEqual ¶
NotBytesEqual checks for !bytes.Equal(actual, expected).
Hint: NotBytesEqual([]byte{}, []byte(nil)) is false (unlike NotDeepEqual).
func (*T) NotContains ¶
NotContains checks is actual not contains substring/element expected.
See Contains about supported actual/expected types and check logic.
func (*T) NotDeepEqual ¶
NotDeepEqual checks for !reflect.DeepEqual(actual, expected).
func (*T) NotErr ¶
NotErr checks is actual error is not the same as expected error.
They must have either different types or values (or one should be nil). Different instances with same type and value will be considered the same error, and so is both nil.
func (*T) NotHasPrefix ¶
NotHasPrefix checks for !strings.HasPrefix(actual, expected).
See HasPrefix about supported actual/expected types and check logic.
func (*T) NotHasSuffix ¶
NotHasSuffix checks for !strings.HasSuffix(actual, expected).
See HasSuffix about supported actual/expected types and check logic.
func (*T) NotHasType ¶
NotHasType checks is actual has not same type as expected.
func (*T) NotImplements ¶
NotImplements checks is actual does not implements interface pointed by expected.
You must use pointer to interface type in expected:
t.NotImplements(os.Stdin, (*fmt.Stringer)(nil))
func (*T) NotInDelta ¶
NotInDelta checks for actual < expected-delta or expected+delta < actual.
All three actual, expected and delta must be either:
- signed integers
- unsigned integers
- floats
- time.Time (in this case delta must be time.Duration)
func (*T) NotInSMAPE ¶
NotInSMAPE checks that actual and expected have a symmetric mean absolute percentage error (SMAPE) is greater than or equal to given smape.
See InSMAPE about supported actual/expected types and check logic.
func (*T) NotMatch ¶
NotMatch checks for !regex.MatchString(actual).
See Match about supported actual/regex types and check logic.
func (*T) NotPanic ¶
NotPanic checks is actual() don't panics.
It is able to detect panic(nil)… but you should try to avoid using this.
func (*T) Panic ¶
Panic checks is actual() panics.
It is able to detect panic(nil)… but you should try to avoid using this.
func (*T) PanicMatch ¶
PanicMatch checks is actual() panics and panic text match regex.
Regex type can be either *regexp.Regexp or string.
In case of panic(nil) it will match like panic("<nil>").
func (*T) PanicNotMatch ¶
PanicNotMatch checks is actual() panics and panic text not match regex.
Regex type can be either *regexp.Regexp or string.
In case of panic(nil) it will match like panic("<nil>").
func (*T) Parallel ¶
func (t *T) Parallel()
Parallel implements an internal workaround which have no visible effect, so you should just call t.Parallel() as you usually do - it will work as expected.
func (*T) Should ¶
Should use user-provided check function to do actual check.
anyShouldFunc must have type ShouldFunc1 or ShouldFunc2. It should return it's name and true if check was successful. There is no need to call t.Error in anyShouldFunc - this will be done automatically when it returns.
args must contain at least 1 element for ShouldFunc1 and at least 2 elements for ShouldFunc2. Rest of elements will be processed as usual msg ...interface{} param.
Example:
func bePositive(_ *check.T, actual interface{}) bool {
return actual.(int) > 0
}
func TestCustomCheck(tt *testing.T) {
t := check.T{tt}
t.Should(bePositive, 42, "custom check!!!")
}