Go-Lean Assert
Lightweight generic assertion library written in Go.
About
Assert aims to stay minimalistic and promotes code readability by using expressive condition names while maximizing
type safety via the use of generics.
Install
go get github.com/go-lean/assert
Example
Assertions are being done via one of the two packages provided. The should
package is asserting test conditions without
terminating the current test on failure, while the must
package does the opposite and terminates as soon as a condition
fails to succeed.
package test
import (
"github.com/go-lean/assert"
"github.com/go-lean/assert/must"
"github.com/go-lean/assert/should"
"testing"
)
func TestSomething(t *testing.T) {
// ...preparations
// acting
results, err := service.DoSomething(ctx, ...)
// assertions
must.BeNilError(t, err, "the operation must have succeeded")
should.BeOfLen(t, results, 2, "should have affected two users")
should.Contain(t, results, userID, "current user should be affected", userID)
}
When failing a should
condition the test will fail, but it will not terminate until a must
condition fails, or the
test is either done or terminated in some other way.
Should
In cases where you want to evaluate several test conditions even if one of them fails, you can use the should
package.
It marks the failures within the current test, but doesn't prevent test conditions that follow from being evaluated.
should.BeNilError(t, err) // even if this fails
should.BeInRange(t, num, 1, 10) // this will still be evaluated
In certain cases it makes no sense to continue evaluating after a failure, so you would like to terminate the current
test. One way of doing this would be to call the OtherwiseBail()
method on the assertion result.
should.BeNilError(t, err).OtherwiseBail() // if this fails
should.BeInRange(t, num, 1, 10) // this and any following conditions will not be evaluated
In the same time probably a cleaner way of expressing the importance of the successful outcome of a certain condition is
to describe it using the must
package.
Must
While being a mere wrapper around the should
package, the must
package provides the option to terminate the current
test after each of its conditions in the case of a failure. Internally it just calls the should
equivalent of the
chosen condition followed by a call to OterwiseBail()
, so nothing fancy there.
Best Practices
Meaningful messages
Make sure to use the messages to add some context to the test conditions instead of relying on the plain assert messages.
expected len to be '3'
is far less helpful of a message than should have sent 3 messages to broker
should.BeOfLen(t, messages, l, "should have sent", l, "messages to broker")
Type safety
Most methods are utilizing generics in order to provide type safety and avoid the use of reflection. Make sure you use
those methods and not the ones marked with 'Deep' keywords, as they provide the ability to process items, that are not
comparable, but come at the cost of type safety and reflection calls.
must
vs should
Make sure you always use must
when it makes no sense to continue evaluating the current test. For example, if a
database call in an integration test fails, there is probably no reason to evaluate any of the conditions that follow.