Documentation
¶
Overview ¶
Package assert is a minimalist test assertion helper library.
Philosophy ¶
Tests usually should not fail. When they do fail, the failure should be repeatable. Therefore, it doesn't make sense to spend a lot of time writing good test messages. (This is unlike error messages, which should happen fairly often, and in production, irrepeatably.) Package assert is designed to simply fail a test quickly and quietly if a condition is not met with a reference to the line number of the failing test. If the reason for having the test is not immediately clear from context, you can write a comment, like normal code. If you do need more extensive reporting to figure out why a test is failing, use *testing.T.Log to capture more information.
The assertions in assert package are methods of the Tester type, which captures a *testing.T or *testing.B and can either call testing.TB.Fail or testing.TB.FailNow on failure depending on how you want the assertions to work.
Most tests just need simple equality testing, which is handled by Tester.Equal (for comparable types), Tester.SlicesEqual (for slices of comparable types), and Tester.DeepEqual (which relies on reflect.DeepEqual). Another common test is that a string or byte slice should contain or not some substring, which is handled by Tester.Match and Tester.NotMatch. Rather than package assert providing every possible test helper, you are encouraged to write your own advanced helpers for use with Tester.True, while package assert takes away the drudgery of writing yet another simple func nilErr(t *testing.T, err) { ... }.
The github.com/earthboundkid/assert/testfile subpackage has functions that make it easy to write file-based tests that ensure that the output of some transformation matches a golden file. Subtests can automatically be run for all files matching a glob pattern, such as testfile.Run(t, "testdata/*/input.txt", ...). If the test fails, the failure output will be written to a file, such as "testdata/basic-test/-failed-output.txt", and then the output can be examined via diff testing with standard tools. Set the environmental variable TESTFILE_UPDATE to update the golden file.
Example ¶
be := assert.Continue(&mockingT{})
be.
Equal("hello", "world"). // bad
Equal("goodbye", "goodbye") // good
be.
NotEqual("hello", "world"). // good
NotEqual("goodbye", "goodbye") // bad
s := []int{1, 2, 3}
be.
SlicesEqual([]int{1, 2, 3}, s). // good
SlicesEqual([]int{3, 2, 1}, s) // bad
f := be.OK(os.Open("nosuchfile")) // bad
be.Zero(f) // good
var err error
be.
Zero(err). // good
ErrorIs(nil, err). // good
NotZero(err). // bad
ErrorIs(err, os.ErrPermission) // bad
err = errors.New("(O_o)")
be.ErrorAsType[*os.PathError](err) // bad
be.NotZero(err) // good
type mytype string
var mystring mytype = "hello, world"
be.
Match(mystring, `world`). // good
Match(mystring, `World`). // bad
Match([]byte("\a\b\x00\r\t"), `^\W*$`). // good
NotMatch([]byte("\a\b\x00\r\t"), `^\W*$`) // bad
seq := strings.FieldsSeq("1 2 3 4")
be.
EqualLength(seq, 4). // good
EqualLength(seq, 1). // bad
AtLeastLength(seq, 1). // good
AtLeastLength(seq, 5). // bad
AtLeastLength("123", 3). // good
AtLeastLength("123", 4) // bad
Output: want: world; got: hello got: goodbye got: [3 2 1]; want: [1 2 3] err != nil: open nosuchfile: no such file or directory got: <nil> got errors.Is(<nil>, permission denied) == false got errors.AsType[*fs.PathError]((O_o)) == false missing match: /World/ !~ "hello, world" unexpected match: /^\W*$/ =~ "\a\b\x00\r\t" want len(seq) == 1; got at least 2 want len(seq) >= 5; got 4 want len(seq) >= 4; got 3
Index ¶
- func Catch(fn func()) (r any)
- func Truthy[T any](v T) bool
- type Tester
- func (be Tester) AtLeastLength(seq any, want int) Tester
- func (be Tester) DeepEqual[T any](got, want T) Tester
- func (be Tester) Equal[T comparable](got, want T) Tester
- func (be Tester) EqualLength(seq any, want int) Tester
- func (be Tester) ErrorAsType[T error](got error) T
- func (be Tester) ErrorIs(got, target error) Tester
- func (be Tester) False(value bool) Tester
- func (be Tester) Match[byteseq ~string | ~[]byte](got byteseq, pattern string) Tester
- func (be Tester) NotEqual[T comparable](got, bad T) Tester
- func (be Tester) NotMatch[byteseq ~string | ~[]byte](got byteseq, pattern string) Tester
- func (be Tester) NotZero[T any](value T) Tester
- func (be Tester) OK[T any](value T, err error) T
- func (be Tester) Panicked(fn func()) Tester
- func (be Tester) SlicesEqual[T comparable](got, want []T) Tester
- func (be Tester) True(value bool) Tester
- func (be Tester) Zero[T any](value T) Tester
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Catch ¶
func Catch(fn func()) (r any)
Catch runs the callback and returns the recovered panic, if any.
func Truthy ¶
Truthy returns
- !v.IsZero(), for types with an IsZero() method.
- len(v) != 0, for slices and maps.
- v != the zero value of T, for all other types.
Example ¶
package main
import (
"fmt"
"github.com/earthboundkid/assert"
)
func main() {
fmt.Printf("%#v is %t-ish\n", 0, assert.Truthy(0))
fmt.Printf("%#v is %t-ish\n", 1, assert.Truthy(1))
fmt.Printf("%#v is %t-ish\n", "", assert.Truthy(""))
fmt.Printf("%#v is %t-ish\n", "hi", assert.Truthy("hi"))
fmt.Printf("%#v is %t-ish\n", error(nil), assert.Truthy[error](nil))
}
Output: 0 is false-ish 1 is true-ish "" is false-ish "hi" is true-ish <nil> is false-ish
Types ¶
type Tester ¶
type Tester struct {
// contains filtered or unexported fields
}
Tester is a type that wraps a *testing.T or *testing.B and adds methods for doing assertion tests against that test manager.
The methods of testing.TB that Tester uses are Helper, Logf, and FailNow (for FailNow) or Fail (for Continue).
func Continue ¶
Continue returns a Tester will continue testing even after an assertion failure. It calls *testing.T.Fail.
func FailNow ¶
FailNow returns a Tester will end the test after an assertion failure with *testing.T.FailNow.
func (Tester) AtLeastLength ¶
AtLeastLength asserts that seq has a length that is at least want.
The type of seq must be array, array pointer, slice, map, string, channel, iter.Seq, or iter.Seq2. For channels and iterators, the values are consumed to get the sequence length.
func (Tester) DeepEqual ¶
DeepEqual asserts got is reflect.DeepEqual to want.
Prefer to use Tester.SlicesEqual if possible.
Example ¶
be := assert.Continue(&mockingT{})
// good
m1 := map[int]bool{1: true, 2: false}
m2 := map[int]bool{1: true, 2: false}
be.DeepEqual(m1, m2)
// bad
var s1 []int
s2 := []int{}
be.DeepEqual(s1, s2) // DeepEqual is picky about nil vs. len 0
Output: reflect.DeepEqual([]int(nil), []int{}) == false
func (Tester) Equal ¶
func (be Tester) Equal[T comparable](got, want T) Tester
Equal asserts that got == want.
func (Tester) EqualLength ¶
EqualLength asserts that seq has a length that is exactly want.
The type of seq must be array, array pointer, slice, map, string, channel, iter.Seq, or iter.Seq2. For channels and iterators, the values are consumed to get the sequence length.
func (Tester) ErrorAsType ¶
ErrorAsType asserts that errors.AsType can unwrap got as T.
func (Tester) NotEqual ¶
func (be Tester) NotEqual[T comparable](got, bad T) Tester
NotEqual asserts that got != want.
func (Tester) NotMatch ¶
NotMatch asserts got does not matches the regexp pattern.
The pattern must compile.
func (Tester) OK ¶
OK asserts that error is nil and returns value. Typical use is like
v := be.OK(canFail())
Example ¶
be := assert.Continue(&mockingT{})
// be.OK asserts the error returned is nil
// and returns the value for subsequent testing.
f := be.OK(os.Open("nosuchfile"))
if f != nil {
f.Close()
}
Output: err != nil: open nosuchfile: no such file or directory
func (Tester) Panicked ¶
Panicked asserts that fn panics when run.
Example ¶
be := assert.Continue(&mockingT{})
divide := func(num, denom int) int {
return num / denom
}
// Test that division by zero panics
be.Panicked(func() {
divide(1, 0)
})
// Because a panic fails a test by default,
// testing that an operation does not panic is less necessary,
// but may be helpful in a table test.
for _, testcase := range []struct {
num, denom, want int
shouldPanic bool
}{
{0, 1, 0, false},
{1, 1, 1, false},
{1, 0, 0xbadc0ffee, true},
{0, 0, 0xbadc0ffee, true},
} {
got := 0xbadc0ffee
panicVal := assert.Catch(func() {
got = divide(testcase.num, testcase.denom)
})
be.Equal(got, testcase.want)
be.Equal(panicVal != nil, testcase.shouldPanic)
}
func (Tester) SlicesEqual ¶
func (be Tester) SlicesEqual[T comparable](got, want []T) Tester
SlicesEqual asserts that slices.Equal(got, want).