Skip to content

Repository files navigation

A simple assertion library using Go generics

PkgGoDevCIGo Report CardSlack chat

This library is inspired by testify/require, but with a significantly reduced API surface based on empirical use of that package.

It also provides much nicer diff output, eg.

=== RUN TestFail
assert_test.go:14: Expected values to be equal:
assert.Data{
- Str: "foo",
+ Str: "far",
Num: 10,
}
--- FAIL: TestFail (0.00s)

API

Import then use as assert:

import"github.com/alecthomas/assert/v2"

This library has the following API. For all functions, msgAndArgs is used to format error messages using the fmt package.

// Equal asserts that "expected" and "actual" are equal using google/go-cmp.//// If they are not, a diff of the Go representation of the values will be displayed.funcEqual[Tcomparable](t testing.TB, expected, actualT, msgAndArgs...interface{})
// NotEqual asserts that "expected" is not equal to "actual" using google/go-cmp.//// If they are equal the expected value will be displayed.funcNotEqual[Tcomparable](t testing.TB, expected, actualT, msgAndArgs...interface{})
// Zero asserts that a value is its zero value.funcZero[Tcomparable](t testing.TB, valueT, msgAndArgs...interface{})
// NotZero asserts that a value is not its zero value.funcNotZero[Tcomparable](t testing.TB, valueT, msgAndArgs...interface{})
// Contains asserts that "haystack" contains "needle".funcContains(t testing.TB, haystackstring, needlestring, msgAndArgs...interface{})
// NotContains asserts that "haystack" does not contain "needle".funcNotContains(t testing.TB, haystackstring, needlestring, msgAndArgs...interface{})
// EqualError asserts that either an error is non-nil and that its message is what is expected,// or that error is nil if the expected message is empty.funcEqualError(t testing.TB, errerror, errStringstring, msgAndArgs...interface{})
// Error asserts that an error is not nil.funcError(t testing.TB, errerror, msgAndArgs...interface{})
// NoError asserts that an error is nil.funcNoError(t testing.TB, errerror, msgAndArgs...interface{})
// IsError asserts than any error in "err"'s tree matches "target".funcIsError(t testing.TB, err, targeterror, msgAndArgs...interface{})
// NotIsError asserts than no error in "err"'s tree matches "target".funcNotIsError(t testing.TB, err, targeterror, msgAndArgs...interface{})
// Panics asserts that the given function panics.funcPanics(t testing.TB, fnfunc(), msgAndArgs...interface{})
// NotPanics asserts that the given function does not panic.funcNotPanics(t testing.TB, fnfunc(), msgAndArgs...interface{})
// Compare two values for equality and return true or false.funcCompare[Tany](t testing.TB, x, yT) bool// True asserts that an expression is true.funcTrue(t testing.TB, okbool, msgAndArgs...interface{})
// False asserts that an expression is false.funcFalse(t testing.TB, okbool, msgAndArgs...interface{})

Evaluation process

Our empirical data of testify usage comes from a monorepo with around 50K lines of tests.

These are the usage counts for all testify functions, normalised to the base (not Printf()) non-negative(not No(t)?) case for each core function.

2240 Error
1314 Equal
219 True
210 Nil
167 Empty
107 Contains
79 Len
61 False
24 EqualValues
20 EqualError
17 Zero
15 Fail
15 ElementsMatch
9 Panics
7 IsType
6 FileExists
4 JSONEq
3 PanicsWithValue
3 Eventually

The decision for each function was:

Keep

  • Error(t, err) -> frequently used, keep
  • Equal(t, expected, actual) -> frequently used, keep but make type safe
  • True(t, expr) -> frequently used, keep
  • False(t, expr) -> frequently used, keep
  • Empty(t, thing) -> require.Equal(t, len(thing), 0)
  • Contains(t, haystack string, needle string) - the only variant used in our codebase, keep as concrete type
  • Zero(t, value) -> make type safe, keep
  • Panics(t, f) -> useful, keep
  • EqualError(t, a, b) -> useful, keep
  • Nil(t, value) -> frequently used, keep

Not keeping, replace with ...

  • ElementsMatch(t, a, b) - use peterrk/slices or stdlib sort support once it lands.
  • IsType(t, a, b) -> require.Equal(t, reflect.TypeOf(a).String(), reflect.TypeOf(b).String())
  • FileExists() -> very little use, drop
  • JSONEq() -> very little use, drop
  • PanicsWithValue() -> very little use, drop
  • Eventually() -> very little use, drop
  • Contains(t, haystack []T, needle T) - very little use, replace with
  • Contains(t, haystack map[K]V, needle K) - very little use, drop
  • Len(t, v, n) -> cannot be implemented as a single function with genericsEqual(t, len(v), n)
  • EqualValues() - Equal(t, TYPE(a), TYPE(b))
  • Fail() -> t.Fatal()

About

A simple assertion library using Go generics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages