Extensible, type-safe, fluent assertion Go library.
Please ⭐ Star
this repository if you find it valuable and worth maintaining.
The fluent API makes the assertion code easier to read and write (more).
The generics (type parameters) make the usage type-safe.
The library is extensible by design.
In general, avoid using assertion libraries. Use this library if you still have a preference to use one. Consider using
github.com/google/go-cmp
and writing custom helpers instead.
package test
import (
"testing"
"github.com/fluentassert/verify"
)
func Foo() (string, error) {
return "wrong", nil
}
func TestFoo(t *testing.T) {
got, err := Foo()
verify.NoError(err).Require(t) // Require(f) uses t.Fatal(f), stops execution if fails
verify.String(got).Equal("ok").Assert(t) // Assert(f) uses t.Error(f), continues execution if fails
}
$ go test
--- FAIL: TestFoo (0.00s)
basic_test.go:17:
the objects are not equal
got: "wrong"
want: "ok"
⚠ Do not forget calling
Assert(t)
or Require(t)
which executes the actual assertion.
Out-of-the-box the package provides fluent assertions for the following types. The more specific function you use, the more assertions you get.
Go type | Assertion entry point |
---|---|
interface{} (any ) |
verify.Any() |
comparable |
verify.Obj() |
constraints.Ordered |
verify.Ordered() |
constraints.Number |
verify.Number() |
string |
verify.String() |
error |
verify.Error() |
[]T (slice) |
verify.Slice() |
map[K]V (map) |
verify.Map() |
Below you can find some convenience functions.
For testing deep equality use
DeepEqual()
or NotDeepEqual()
.
package test
import (
"testing"
"github.com/fluentassert/verify"
)
type A struct {
Str string
Bool bool
Slice []int
}
func TestDeepEqual(t *testing.T) {
got := A{Str: "wrong", Slice: []int{1, 4}}
verify.Any(got).DeepEqual(
A{Str: "string", Bool: true, Slice: []int{1, 2}},
).Assert(t)
}
$ go test
--- FAIL: TestDeepEqual (0.00s)
deepeq_test.go:20:
mismatch (-want +got):
test.A{
- Str: "string",
+ Str: "wrong",
- Bool: true,
+ Bool: false,
Slice: []int{
1,
- 2,
+ 4,
},
}
The library contains many collection assertion. Below is an example of checking unordered equality.
package test
import (
"testing"
"github.com/fluentassert/verify"
)
func TestSlice(t *testing.T) {
got := []int { 3, 1, 2 }
verify.Slice(got).Equivalent([]int { 2, 3, 4 }).Assert(t)
}
$ go test
--- FAIL: TestSlice (0.00s)
slice_test.go:12:
not equivalent
got: [3 1 2]
want: [2 3 4]
extra got: [1]
extra want: [4]
For asynchronous testing you can use
verify.Eventually()
or verify.EventuallyChan()
.
package test
import (
"net/http"
"testing"
"time"
"github.com/fluentassert/verify"
)
func TestPeriodic(t *testing.T) {
verify.Eventually(10*time.Second, time.Second, func() verify.FailureMessage {
client := http.Client{Timeout: time.Second}
resp, err := client.Get("http://not-existing:1234")
if err != nil {
return verify.NoError(err)
}
return verify.Number(resp.StatusCode).Lesser(300)
}).Assert(t)
}
$ go test
--- FAIL: TestPeriodic (10.00s)
async_test.go:19:
function never passed, last failure message:
Get "http://not-existing:1234": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
For the most basic scenarios, you can use one of the
Check()
,
Should()
,
ShouldNot()
assertions.
package test
import (
"strings"
"testing"
"github.com/fluentassert/verify"
)
func TestShould(t *testing.T) {
got := "wrong"
chars := "abc"
verify.Any(got).Should(func(got string) bool {
return strings.ContainsAny(got, chars)
}).Assertf(t, "does not contain any of: %s", chars)
}
$ go test
--- FAIL: TestShould (0.00s)
should_test.go:16: does not contain any of: abc
object does not meet the predicate criteria
got: "wrong"
For testing panics use verify.Panics()
and verify.NotPanics()
.
You can create a function that returns FailureMessage
.
Use verify.And()
and verify.Or()
functions together with Prefix()
method to create complex assertions.
package test
import (
"testing"
"github.com/fluentassert/verify"
)
type A struct {
Str string
Ok bool
}
func TestCustom(t *testing.T) {
got := A{Str: "something was wrong"}
verifyA(got).Assert(t)
}
func verifyA(got A) verify.FailureMessage {
return verify.And(
verify.String(got.Str).Contain("ok").Prefix("got.String: "),
verify.True(got.Ok).Prefix("got.Ok: "),
)
}
$ go test
--- FAIL: TestCustom (0.00s)
custom_test.go:17:
got.String: the value does not contain the substring
got: "something was wrong"
substr: "ok"
got.Ok: the value is false
You can take advantage of the FailureMessage
and Fluent*
types
to create your own fluent assertions for a given type.
For reference, take a look at the implementation of existing fluent assertions in this repository (for example comparable.go).
Minimal supported Go version is 1.18.
See CONTRIBUTING.md if you want to help.
fluentassert is licensed under the terms of the MIT license.
github.com/google/go-cmp
(license: BSD-3-Clause)
is the only third-party dependency.