An assertion package with a minimal API, yet powerful enough to cover most use cases.
The assert package is designed to provide a more configurable and type-safe alternative to the popular testify/assert package.
Have you ever struggled with comparing complex structs in your tests? One that use decimal.Decimal, time.Time, or uuid.UUID types? Or perhaps you wanted to ignore automatically generated fields, such as ID or CreatedAt, in your struct comparisons?
assert allows for more flexible assertions, such as ignoring unexported fields or skipping empty fields in struct comparisons.
package main
import (
"errors"
"fmt"
"io"
"io/fs"
"testing"
"github.com/krhubert/assert"
)
func TestXYZ(t *testing.T) {
// assert checks if value implements Equal() bool method
// and uses it to compare values. This makes it possible
// to compare e.g. time.Time values.
now := time.Now()
assert.Equal(t, now, now)
// assert is type safe, so this will not compile
// assert.Equal(t, 1, "1")
// assert do not compare pointers, but values they point to
a, b := 1, 1
assert.Equal(t, &a, &b)
// assert checks for errors
assert.Error(t, errors.New("error"))
assert.NoError(t, nil)
// assert checks if error contains a target value
// like string, error or struct
err := fmt.Errorf(
"closed socket: %w %w",
io.EOF,
&fs.PathError{Op: "read", Path: "socket", Err: io.ErrClosedPipe},
)
assert.ErrorContains(t, err, "closed socket")
assert.ErrorContains(t, err, io.EOF)
var pathError *fs.PathError
assert.ErrorContains(atb, err, &pathError)
// assert checks if function panics or not
assert.Panic(t, func() { panic(0) })
assert.NotPanic(t, func() { })
// assert can be used to check errors in defer functions
defer assert.Defer(t, func() error { return file.Close() })()
// assert can be used to check if a value is of a specific type
gs := TypeAssert[fmt.GoStringer](t, time.Time{})
}package main
import (
"errors"
"fmt"
"io"
"io/fs"
"testing"
_ "github.com/mattn/go-sqlite3"
"go.uber.org/mock/gomock"
"github.com/krhubert/assert"
)
type ExampleTestSuite struct {
assert.Suite
i int
ctrl *gomock.Controller
db *sql.DB
}
func (s *ExampleTestSuite) Setup(t *testing.T) {
s.i = 4
s.ctrl = gomock.NewController(t)
db, err := sql.Open("sqlite3", ":memory:")
assert.NoError(t, err)
s.db = db
}
func (s *ExampleTestSuite) Teardown(t *testing.T) {
s.i = 0
assert.NoError(t, s.db.Close())
}
func TestExample(t *testing.T) {
ts := assert.Setup[ExampleTestSuite](t)
row := ts.db.QueryRow("select date()")
var date string
assert.NoError(ts, row.Scan(&date))
assert.NoError(ts, row.Err())
}package assert
import (
"testing"
"time"
"github.com/google/uuid"
"github.com/shopspring/decimal"
"github.com/stretchr/testify/require"
)
func TestExampleEqual(t *testing.T) {
type User struct {
Id uuid.UUID
Email string
CreatedAt time.Time
Balance decimal.Decimal
active bool
}
loc, _ := time.LoadLocation("Europe/Warsaw")
// db.CreateUser("test@example.com")
createdAt := time.Now()
user := User{
Id: uuid.New(),
Email: "test@example.com",
CreatedAt: createdAt,
Balance: decimal.NewFromFloat(1),
active: true,
}
want := User{
Email: "test@example.com",
CreatedAt: createdAt.In(loc),
Balance: decimal.RequireFromString("1"),
}
}Running go test on:
| Assert | Testify |
|---|---|
assert.Equal(t, user, want, IgnoreUnexported(), SkipEmptyFields()) |
require.Equal(t, user, want) |