Awesome
fluentassert
Extensible, type-safe, fluent assertion Go library.
Please ⭐ Star
this repository if you find it valuable and worth maintaining.
Description
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.
Quick start
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.
Supported types
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.
Deep equality
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,
},
}
Collection assertions
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]
Periodic polling
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)
Custom predicates
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"
Panics
For testing panics use verify.Panics()
and verify.NotPanics()
.
Custom assertion function
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
Extensibility
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).
Supported Go versions
Minimal supported Go version is 1.18.
Contributing
See CONTRIBUTING.md if you want to help.
License
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.