Go test assertion library.
- Test assertion (equal, comparison, nil, empty, length, error, etc...)
- No reflection (uses generics)
- Customization (print and compare values)
A simple assertion:
assert.Equal(t, value, 1)
By default, assertions fail with Fatal()
.
It can be changed with the Report()
option:
assert.Equal(t, value, 1, assert.Report(t.Error))
The report message can be customized:
assert.Equal(t, value, 1, assert.MessageWrap("test"))
This assertion library is an experiment to see if it is possible to do better than github.com/stretchr/testify
, by using generics.
Here is an example of an issue with github.com/stretchr/testify
:
func Test(t *testing.T) {
value := getValue()
require.Equal(t, 1, value)
}
func getValue() int64 {
return 1
}
Surprinsingly, this test fails with this error:
Error: Not equal:
expected: int(1)
actual : int64(1)
This issue is caused by the types, which are no identical (the 1
constant is an int
and not an int64
), and it's possible to fix it:
Convert the value to int64
:
require.Equal(t, int64(1), value)
Use EqualValues()
which converts the values to the same type:
require.EqualValues(t, 1, value)
But the internal implementation is not simple: it requires heavy usage of reflection, and the code is quite complex.
What if we could simply use the ==
operator ?
This is the solution chosen by this library.
It uses generics to do the comparison, and it works with any comparable type:
func Equal[T comparable](tb testing.TB, v1, v2 T, opts ...Option) bool {
tb.Helper()
ok := v1 == v2
if !ok {
Fail(...)
}
return ok
}
assert.Equal(t, 1, value)
The constant 1
is automatically converted to the type of the value
variable without using reflection.
However, this approchach has a limitation: it requires to write a different assertion function for each "kind" (map, slice, etc...)
The default behavior can be customized:
DeepEqualer
allows to customize how values are compared withDeepEqual()
.ValueStringer
allows to customize how values are printed.ErrorStringer
allows to customize how errors are printed.
I think it's a great library, but I wanted to try something different. I also wanted to try generics, and to see if it was possible to make an assertion library without reflection.
- For slices use SliceNil() and SliceNotNil()
- For maps use MapNil() and MapNotNil()
- For comparable types use Zero() and NotZero()