Documentation
¶
Overview ¶
Example (ConfigureDiffFunc) ¶
package main
import (
"fmt"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
assert.DiffFunc = func(value, othValue any) string {
return fmt.Sprintf("%#v | %#v", value, othValue)
}
var tb testing.TB
assert.Equal(tb, "foo", "bar")
}
Index ¶
- Variables
- func AnyOf(tb testing.TB, blk func(a *A), msg ...Message)
- func Contain(tb testing.TB, haystack, needle any, msg ...Message)
- func ContainExactly[T any](tb testing.TB, v, oth T, msg ...Message)
- func Empty(tb testing.TB, v any, msg ...Message)
- func Equal[T any](tb testing.TB, v, oth T, msg ...Message)
- func Error(tb testing.TB, err error, msg ...Message)
- func ErrorIs(tb testing.TB, err, oth error, msg ...Message)
- func Eventually[T time.Duration | int](tb testing.TB, durationOrCount T, blk func(it It))
- func False(tb testing.TB, v bool, msg ...Message)
- func Match[T string | []byte](tb testing.TB, v T, expr string, msg ...Message)
- func Nil(tb testing.TB, v any, msg ...Message)
- func NoError(tb testing.TB, err error, msg ...Message)
- func NotContain(tb testing.TB, haystack, v any, msg ...Message)
- func NotEmpty(tb testing.TB, v any, msg ...Message)
- func NotEqual[T any](tb testing.TB, v, oth T, msg ...Message)
- func NotMatch[T string | []byte](tb testing.TB, v T, expr string, msg ...Message)
- func NotNil(tb testing.TB, v any, msg ...Message)
- func NotPanic(tb testing.TB, blk func(), msg ...Message)
- func NotWithin(tb testing.TB, timeout time.Duration, blk func(context.Context), ...)
- func OneOf[V any](tb testing.TB, vs []V, blk func(it It, got V), msg ...Message)
- func Panic(tb testing.TB, blk func(), msg ...Message) any
- func Read[T string | []byte](tb testing.TB, v T, r io.Reader, msg ...Message)
- func ReadAll(tb testing.TB, r io.Reader, msg ...Message) []byte
- func RegisterEqual[T any, FN EqualFunc[T]](fn FN) struct{}
- func Sub[T any](tb testing.TB, haystack, needle []T, msg ...Message)
- func True(tb testing.TB, v bool, msg ...Message)
- func Within(tb testing.TB, timeout time.Duration, blk func(context.Context), ...)
- type A
- type Asserter
- func (a Asserter) AnyOf(blk func(a *A), msg ...Message)
- func (a Asserter) Contain(haystack, needle any, msg ...Message)
- func (a Asserter) ContainExactly(v, oth any, msg ...Message)
- func (a Asserter) Empty(v any, msg ...Message)
- func (a Asserter) Equal(v, oth any, msg ...Message)
- func (a Asserter) Error(err error, msg ...Message)
- func (a Asserter) ErrorIs(err, oth error, msg ...Message)
- func (a Asserter) Eventually(durationOrCount any, blk func(it It))
- func (a Asserter) False(v bool, msg ...Message)
- func (a Asserter) Match(v, expr string, msg ...Message)
- func (a Asserter) Nil(v any, msg ...Message)
- func (a Asserter) NoError(err error, msg ...Message)
- func (a Asserter) NotContain(haystack, v any, msg ...Message)
- func (a Asserter) NotEmpty(v any, msg ...Message)
- func (a Asserter) NotEqual(v, oth any, msg ...Message)
- func (a Asserter) NotMatch(v, expr string, msg ...Message)
- func (a Asserter) NotNil(v any, msg ...Message)
- func (a Asserter) NotPanic(blk func(), msg ...Message)
- func (a Asserter) NotWithin(timeout time.Duration, blk func(context.Context), msg ...Message)
- func (a Asserter) OneOf(values any, blk any, msg ...Message)
- func (a Asserter) Panic(blk func(), msg ...Message) any
- func (a Asserter) Read(v any, r io.Reader, msg ...Message)
- func (a Asserter) ReadAll(r io.Reader, msg ...Message) []byte
- func (a Asserter) Sub(slice, sub any, msg ...Message)
- func (a Asserter) True(v bool, msg ...Message)
- func (a Asserter) Within(timeout time.Duration, blk func(context.Context), msg ...Message)
- type EqualFunc
- type It
- type Message
- type Retry
- type RetryStrategy
- type RetryStrategyFunc
- type Waiter
Examples ¶
- Package (ConfigureDiffFunc)
- AnyOf (AnyOfExpectedOutcome)
- AnyOf (AnyOfTheElement)
- AnyOf (FanOutPublishing)
- AnyOf (ListOfCompositedStructuresWhereOnlyTheEmbededValueIsRelevant)
- AnyOf (ListOfInterface)
- AnyOf (ListOfStructuresWithIrrelevantValues)
- AnyOf (StructWithManyAcceptableState)
- Asserter.AnyOf
- Asserter.Contain
- Asserter.ContainExactly
- Asserter.Empty
- Asserter.Equal
- Asserter.Equal (IsEqualFunctionThatSupportsErrorReturning)
- Asserter.Equal (WithEqualMethod)
- Asserter.Equal (WithIsEqualMethod)
- Asserter.Error
- Asserter.ErrorIs
- Asserter.Eventually
- Asserter.False
- Asserter.Match
- Asserter.Nil
- Asserter.NoError
- Asserter.NotContain
- Asserter.NotEmpty
- Asserter.NotEqual
- Asserter.NotMatch
- Asserter.NotNil
- Asserter.NotPanic
- Asserter.NotWithin
- Asserter.OneOf
- Asserter.Panic
- Asserter.Read
- Asserter.ReadAll
- Asserter.Sub
- Asserter.True
- Asserter.Within
- Contain
- ContainExactly
- Empty
- Equal
- Error
- ErrorIs
- Eventually
- False
- MakeRetry
- MakeRetry (ByCount)
- MakeRetry (ByTimeout)
- Match
- Message
- Must
- Nil
- NoError
- NotContain
- NotEmpty
- NotEqual
- NotMatch
- NotNil
- NotPanic
- NotWithin
- OneOf
- Panic
- Read
- ReadAll
- Retry
- Retry (AsContextOption)
- Retry (ByCount)
- Retry (ByCustomRetryStrategy)
- Retry (ByTimeout)
- Retry (Count)
- Should
- Sub
- True
- Waiter.Wait
- Waiter.While
- Within
Constants ¶
This section is empty.
Variables ¶
var DiffFunc diffFn = pp.DiffFormat[any]
DiffFunc is the function that will be used to print out two object if they are not equal. You can use your preferred diff implementation if you are not happy with the pretty print diff format.
Functions ¶
func AnyOf ¶
AnyOf is an assertion helper that deems the test successful if any of the declared assertion cases pass. This is commonly used when multiple valid formats are acceptable or when working with a list where any element meeting a certain criteria is considered sufficient.
Example (AnyOfExpectedOutcome) ¶
package main
import (
"go.llib.dev/testcase/random"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
var rnd = random.New(random.CryptoSeed{})
outcome := rnd.Bool()
assert.AnyOf(tb, func(a *assert.A) {
a.Case(func(it assert.It) {
it.Must.True(outcome)
})
a.Case(func(it assert.It) {
it.Must.False(outcome)
})
})
}
Example (AnyOfTheElement) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
var list []interface {
Foo() int
Bar() bool
Baz() string
}
assert.AnyOf(tb, func(anyOf *assert.A) {
for _, testingCase := range list {
anyOf.Case(func(it assert.It) {
it.Must.True(testingCase.Bar())
})
}
})
}
Example (FanOutPublishing) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
type ExamplePublisherEvent struct{ V int }
type ExamplePublisher struct{}
func (ExamplePublisher) Publish(ExamplePublisherEvent) {}
func (ExamplePublisher) Subscribe(func(ExamplePublisherEvent)) {}
func (ExamplePublisher) Wait() {}
func (ExamplePublisher) Close() error { return nil }
func main() {
var tb testing.TB
publisher := ExamplePublisher{}
anyOf := &assert.A{TB: tb, Fail: tb.FailNow}
for i := 0; i < 42; i++ {
publisher.Subscribe(func(event ExamplePublisherEvent) {
anyOf.Case(func(it assert.It) {
it.Must.Equal(42, event.V)
})
})
}
publisher.Publish(ExamplePublisherEvent{V: 42})
publisher.Wait()
assert.Must(tb).Nil(publisher.Close())
anyOf.Finish()
}
Example (ListOfCompositedStructuresWhereOnlyTheEmbededValueIsRelevant) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
type BigStruct struct {
ID string // not relevant for the test
A, B, C, D, E int // not relevant data as well
WrappedStruct struct {
A, B, C int // relevant data for the test
}
}
anyOf := assert.A{TB: tb, Fail: tb.FailNow}
for _, v := range []BigStruct{} {
anyOf.Case(func(it assert.It) {
it.Must.Equal(42, v.WrappedStruct.A)
it.Must.Equal(1, v.WrappedStruct.B)
it.Must.Equal(2, v.WrappedStruct.C)
})
}
anyOf.Finish()
}
Example (ListOfInterface) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
type ExampleInterface interface {
Foo() int
Bar() bool
Baz() string
}
anyOf := assert.A{TB: tb, Fail: tb.FailNow}
for _, v := range []ExampleInterface{} {
anyOf.Case(func(it assert.It) {
it.Must.True(v.Bar())
})
}
anyOf.Finish()
}
Example (ListOfStructuresWithIrrelevantValues) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
type StructWithDynamicValues struct {
IrrelevantStateValue int // not relevant data for the test
ImportantValue int
}
anyOf := assert.A{TB: tb, Fail: tb.FailNow}
for _, v := range []StructWithDynamicValues{} {
anyOf.Case(func(it assert.It) {
it.Must.Equal(42, v.ImportantValue)
})
}
anyOf.Finish()
}
Example (StructWithManyAcceptableState) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
type ExampleStruct struct {
Type string
A, B, C int
}
var es ExampleStruct
anyOf := assert.A{TB: tb, Fail: tb.FailNow}
anyOf.Case(func(it assert.It) {
it.Must.Equal(`foo`, es.Type)
it.Must.Equal(1, es.A)
it.Must.Equal(2, es.B)
it.Must.Equal(3, es.C)
})
anyOf.Case(func(it assert.It) {
it.Must.Equal(`foo`, es.Type)
it.Must.Equal(3, es.A)
it.Must.Equal(2, es.B)
it.Must.Equal(1, es.C)
})
anyOf.Case(func(it assert.It) {
it.Must.Equal(`bar`, es.Type)
it.Must.Equal(11, es.A)
it.Must.Equal(12, es.B)
it.Must.Equal(13, es.C)
})
anyOf.Case(func(it assert.It) {
it.Must.Equal(`baz`, es.Type)
it.Must.Equal(21, es.A)
it.Must.Equal(22, es.B)
it.Must.Equal(23, es.C)
})
anyOf.Finish()
}
func Contain ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Contain([]int{1, 2, 3}, 3, "optional assertion explanation")
assert.Must(tb).Contain([]int{1, 2, 3}, []int{1, 2}, "optional assertion explanation")
assert.Must(tb).Contain(
map[string]int{"The Answer": 42, "oth": 13},
map[string]int{"The Answer": 42},
"optional assertion explanation")
}
func ContainExactly ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.ContainExactly(tb, []int{1, 2, 3}, []int{2, 3, 1}, "optional assertion explanation") // true
assert.ContainExactly(tb, []int{1, 2, 3}, []int{1, 42, 2}, "optional assertion explanation") // false
}
func Empty ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Empty(tb, "") // ok
assert.Empty(tb, "oh no!") // Fatal
}
func Equal ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Equal(tb, "a", "a")
assert.Equal(tb, 42, 42)
assert.Equal(tb, []int{42}, []int{42})
assert.Equal(tb, map[int]int{24: 42}, map[int]int{24: 42})
}
func Error ¶
Example ¶
package main
import (
"errors"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Error(tb, nil) // fail
assert.Error(tb, errors.New("boom")) // pass
}
func ErrorIs ¶
Example ¶
package main
import (
"errors"
"fmt"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
actualErr := errors.New("boom")
assert.ErrorIs(tb, actualErr, errors.New("boom")) // passes for equality
assert.ErrorIs(tb, fmt.Errorf("wrapped error: %w", actualErr), errors.New("boom")) // passes for wrapped errors
}
func Eventually ¶
Example ¶
package main
import (
"math/rand"
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Eventually(tb, time.Second, func(it assert.It) {
it.Must.True(rand.Intn(1) == 0)
})
}
func False ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.False(tb, false) // ok
assert.False(tb, true) // Fatal
}
func Match ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Match(tb, "42", "[0-9]+")
assert.Match(tb, "forty-two", "[a-z]+")
assert.Match(tb, []byte("forty-two"), "[a-z]+")
}
func Nil ¶
Example ¶
package main
import (
"errors"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Nil(tb, nil) // ok
assert.Nil(tb, errors.New("boom")) // Fatal
}
func NoError ¶
Example ¶
package main
import (
"errors"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.NoError(tb, nil) // pass
assert.NoError(tb, errors.New("boom")) // fail
}
func NotContain ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).NotContain([]int{1, 2, 3}, 42)
assert.Must(tb).NotContain([]int{1, 2, 3}, []int{1, 2, 42})
assert.Must(tb).NotContain(
map[string]int{"The Answer": 42, "oth": 13},
map[string]int{"The Answer": 41})
}
func NotEmpty ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.NotEmpty(tb, "huh...") // ok
assert.NotEmpty(tb, "") // Fatal
}
func NotEqual ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.NotEqual(tb, "a", "b")
assert.Equal(tb, 13, 42)
}
func NotMatch ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.NotMatch(tb, "42", "^[a-z]+")
assert.NotMatch(tb, "forty-two", "^[0-9]+")
assert.NotMatch(tb, []byte("forty-two"), "^[0-9]+")
}
func NotNil ¶
Example ¶
package main
import (
"errors"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.NotNil(tb, errors.New("boom")) // ok
assert.NotNil(tb, nil) // Fatal
}
func NotPanic ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.NotPanic(tb, func() {}) // ok
assert.NotPanic(tb, func() { panic("oh no!") }) // Fatal
}
func NotWithin ¶
Example ¶
package main
import (
"context"
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.NotWithin(tb, time.Second, func(ctx context.Context) {
return // FAIL
})
assert.NotWithin(tb, time.Nanosecond, func(ctx context.Context) {
time.Sleep(time.Second) // OK
})
}
func OneOf ¶
OneOf function checks a list of values and matches an expectation against each element of the list. If any of the elements pass the assertion, then the assertion helper function does not fail the test.
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
values := []string{"foo", "bar", "baz"}
assert.OneOf(tb, values, func(it assert.It, got string) {
it.Must.Equal("bar", got)
}, "optional assertion explanation")
}
func Panic ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
panicValue := assert.Panic(tb, func() { panic("at the disco") }) // ok
assert.Equal(tb, "some expected panic value", panicValue)
assert.Panic(tb, func() {}) // Fatal
}
func Read ¶
Example ¶
package main
import (
"strings"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Read(tb, "expected content", strings.NewReader("expected content")) // pass
assert.Read(tb, "expected content", strings.NewReader("different content")) // fail
}
func ReadAll ¶
Example ¶
package main
import (
"errors"
"strings"
"testing"
"testing/iotest"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
content := assert.ReadAll(tb, strings.NewReader("expected content")) // pass
_ = content
assert.ReadAll(tb, iotest.ErrReader(errors.New("boom"))) // fail
}
func RegisterEqual ¶
func Sub ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Sub(tb, []int{1, 2, 3}, []int{1, 2}, "optional assertion explanation")
}
func True ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.True(tb, true) // ok
assert.True(tb, false) // Fatal
}
func Within ¶
Example ¶
package main
import (
"context"
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Within(tb, time.Second, func(ctx context.Context) {
// OK
})
assert.Within(tb, time.Nanosecond, func(ctx context.Context) {
time.Sleep(time.Second)
// FAIL
})
}
Types ¶
type A ¶ added in v0.145.0
A stands for Any Of, an assertion helper that allows you run A.Case assertion blocks, that can fail, as lone at least one of them succeeds. common usage use-cases:
- list of interface, where test order, or the underlying structure's implementation is irrelevant for the behavior.
- list of big structures, where not all field value relevant, only a subset, like a structure it wraps under a field.
- list of structures with fields that has dynamic state values, which is irrelevant for the given test.
- structure that can have various state scenario, and you want to check all of them, and you expect to find one match with the input.
- fan out scenario, where you need to check in parallel that at least one of the worker received the event.
func (*A) Case ¶ added in v0.145.0
Case will test a block of assertion that must succeed in order to make A pass. You can have as much A.Case calls as you need, but if any of them pass with success, the rest will be skipped. Using Case is safe for concurrently.
type Asserter ¶
func Must ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
// create an assertion helper which will fail the testing context with .Fatal(...) in case of a failed assert.
assert.Must(tb).True(true)
}
func Should ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
// create an assertion helper which will fail the testing context with .Error(...) in case of a failed assert.
assert.Should(tb).True(true)
}
func (Asserter) AnyOf ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
var list []interface {
Foo() int
Bar() bool
Baz() string
}
assert.Must(tb).AnyOf(func(anyOf *assert.A) {
for _, testingCase := range list {
anyOf.Case(func(it assert.It) {
it.Must.True(testingCase.Bar())
})
}
})
}
func (Asserter) Contain ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Contain([]int{1, 2, 3}, 3, "optional assertion explanation")
assert.Must(tb).Contain([]int{1, 2, 3}, []int{1, 2}, "optional assertion explanation")
assert.Must(tb).Contain(map[string]int{"The Answer": 42, "oth": 13}, map[string]int{"The Answer": 42}, "optional assertion explanation")
}
func (Asserter) ContainExactly ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).ContainExactly([]int{1, 2, 3}, []int{2, 3, 1}, "optional assertion explanation") // true
assert.Must(tb).ContainExactly([]int{1, 2, 3}, []int{1, 42, 2}, "optional assertion explanation") // false
}
func (Asserter) Empty ¶
Empty gets whether the specified value is considered empty.
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Empty([]int{}) // pass
assert.Must(tb).Empty([]int{42}) // fail
assert.Must(tb).Empty([42]int{}) // pass
assert.Must(tb).Empty([42]int{42}) // fail
assert.Must(tb).Empty(map[int]int{}) // pass
assert.Must(tb).Empty(map[int]int{42: 24}) // fail
assert.Must(tb).Empty("") // pass
assert.Must(tb).Empty("42") // fail
}
func (Asserter) Equal ¶
Equal allows you to match if two entity is equal.
if entities are implementing IsEqual/Equal function, then it will be used to check equality between each other.
- value.IsEqual(oth T) bool
- value.IsEqual(oth T) (bool, error)
- value.Equal(oth T) bool
- value.Equal(oth T) (bool, error)
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Equal(true, true, "optional assertion explanation")
}
Example (IsEqualFunctionThatSupportsErrorReturning) ¶
package main
import (
"errors"
"testing"
"go.llib.dev/testcase/assert"
)
type ExampleEqualableWithError struct {
IrrelevantExportedField int
relevantUnexportedValue int
IsEqualErr error
}
func (es ExampleEqualableWithError) IsEqual(oth ExampleEqualableWithError) (bool, error) {
return es.relevantUnexportedValue == oth.relevantUnexportedValue, es.IsEqualErr
}
func main() {
var tb testing.TB
expected := ExampleEqualableWithError{
IrrelevantExportedField: 42,
relevantUnexportedValue: 24,
IsEqualErr: errors.New("sadly something went wrong"),
}
actual := ExampleEqualableWithError{
IrrelevantExportedField: 42,
relevantUnexportedValue: 24,
}
assert.Must(tb).Equal(expected, actual) // fails because the error returned from the IsEqual function.
}
Example (WithEqualMethod) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
type ExampleEqualableWithEqual struct {
IrrelevantExportedField int
relevantUnexportedValue int
}
func (es ExampleEqualableWithEqual) IsEqual(oth ExampleEqualableWithEqual) bool {
return es.relevantUnexportedValue == oth.relevantUnexportedValue
}
func main() {
var tb testing.TB
expected := ExampleEqualableWithEqual{
IrrelevantExportedField: 42,
relevantUnexportedValue: 24,
}
actual := ExampleEqualableWithEqual{
IrrelevantExportedField: 4242,
relevantUnexportedValue: 24,
}
assert.Must(tb).Equal(expected, actual) // passes as by IsEqual terms the two value is equal
}
Example (WithIsEqualMethod) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
type ExampleEqualableWithIsEqual struct {
IrrelevantExportedField int
relevantUnexportedValue int
}
func (es ExampleEqualableWithIsEqual) IsEqual(oth ExampleEqualableWithIsEqual) bool {
return es.relevantUnexportedValue == oth.relevantUnexportedValue
}
func main() {
var tb testing.TB
expected := ExampleEqualableWithIsEqual{
IrrelevantExportedField: 42,
relevantUnexportedValue: 24,
}
actual := ExampleEqualableWithIsEqual{
IrrelevantExportedField: 4242,
relevantUnexportedValue: 24,
}
assert.Must(tb).Equal(expected, actual) // passes as by IsEqual terms the two value is equal
}
func (Asserter) Error ¶
Example ¶
package main
import (
"errors"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
asserter := assert.Should(tb)
asserter.Error(nil) // fail
asserter.Error(errors.New("boom")) // pass
}
func (Asserter) ErrorIs ¶
ErrorIs allow you to assert an error value by an expectation. ErrorIs allow asserting an error regardless if it's wrapped or not. Suppose the implementation of the test subject later changes by wrap errors to add more context to the return error.
Example ¶
package main
import (
"errors"
"fmt"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
actualErr := errors.New("boom")
assert.Must(tb).ErrorIs(errors.New("boom"), actualErr) // passes for equality
assert.Must(tb).ErrorIs(errors.New("boom"), fmt.Errorf("wrapped error: %w", actualErr)) // passes for wrapped errors
}
func (Asserter) Eventually ¶ added in v0.144.0
Example ¶
package main
import (
"math/rand"
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Eventually(time.Minute, func(it assert.It) {
it.Must.True(rand.Intn(1) == 0)
})
}
func (Asserter) False ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).False(false, "optional assertion explanation")
}
func (Asserter) Match ¶
Match will match an expression against a given value. Match will fail for both receiving an invalid expression or having the value not matched by the expression. If the expression is invalid, test will fail early, regardless if Should or Must was used.
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Match("42", "[0-9]+")
assert.Must(tb).Match("forty-two", "[a-z]+")
}
func (Asserter) Nil ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Nil(nil, "optional assertion explanation")
}
func (Asserter) NoError ¶
Example ¶
package main
import (
"errors"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
asserter := assert.Should(tb)
asserter.NoError(nil) // pass
asserter.NoError(errors.New("boom")) // fail
}
func (Asserter) NotContain ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).NotContain([]int{1, 2, 3}, 42, "optional assertion explanation")
assert.Must(tb).NotContain([]int{1, 2, 3}, []int{42}, "optional assertion explanation")
assert.Must(tb).NotContain(map[string]int{"The Answer": 42, "oth": 13}, map[string]int{"The Answer": 13}, "optional assertion explanation")
}
func (Asserter) NotEmpty ¶
NotEmpty gets whether the specified value is considered empty.
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).NotEmpty([]int{42}, "optional assertion explanation")
assert.Must(tb).NotEmpty([]int{}) // fail
assert.Must(tb).NotEmpty([]int{42}) // pass
assert.Must(tb).NotEmpty([42]int{}) // fail
assert.Must(tb).NotEmpty([42]int{42}) // pass
assert.Must(tb).NotEmpty(map[int]int{}) // fail
assert.Must(tb).NotEmpty(map[int]int{42: 24}) // pass
assert.Must(tb).NotEmpty("") // fail
assert.Must(tb).NotEmpty("42") // pass
}
func (Asserter) NotEqual ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).NotEqual(true, false, "optional assertion explanation")
}
func (Asserter) NotMatch ¶
NotMatch will check if an expression is not matching a given value. NotMatch will fail the test early for receiving an invalid expression.
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).NotMatch("42", "^[a-z]+")
assert.Must(tb).NotMatch("forty-two", "^[0-9]+")
}
func (Asserter) NotNil ¶
Example ¶
package main
import (
"errors"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).NotNil(errors.New("42"), "optional assertion explanation")
}
func (Asserter) NotPanic ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).NotPanic(func() { /* no boom */ }, "optional assertion explanation")
}
func (Asserter) NotWithin ¶
Example ¶
package main
import (
"context"
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
a := assert.Must(tb)
a.NotWithin(time.Second, func(ctx context.Context) {
return // FAIL
})
a.NotWithin(time.Nanosecond, func(ctx context.Context) {
time.Sleep(time.Second) // OK
})
}
func (Asserter) OneOf ¶ added in v0.145.0
OneOf evaluates whether at least one element within the given values meets the conditions set in the assertion block.
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
values := []string{"foo", "bar", "baz"}
assert.Must(tb).OneOf(values, func(it assert.It, got string) {
it.Must.Equal("bar", got)
}, "optional assertion explanation")
}
func (Asserter) Panic ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Panic(func() { panic("boom") }, "optional assertion explanation")
}
func (Asserter) Read ¶
Example ¶
package main
import (
"strings"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
must := assert.Must(tb)
must.Read("expected content", strings.NewReader("expected content")) // pass
must.Read("expected content", strings.NewReader("different content")) // fail
}
func (Asserter) ReadAll ¶
Example ¶
package main
import (
"errors"
"strings"
"testing"
"testing/iotest"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
must := assert.Must(tb)
content := must.ReadAll(strings.NewReader("expected content")) // pass
_ = content
must.ReadAll(iotest.ErrReader(errors.New("boom"))) // fail
}
func (Asserter) Sub ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).Sub([]int{1, 2, 3}, 3, "optional assertion explanation")
assert.Must(tb).Sub([]int{1, 2, 3}, []int{1, 2}, "optional assertion explanation")
}
func (Asserter) True ¶
Example ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.Must(tb).True(true, "optional assertion explanation")
}
func (Asserter) Within ¶
Example ¶
package main
import (
"context"
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
a := assert.Must(tb)
a.Within(time.Second, func(ctx context.Context) {
// OK
})
a.Within(time.Nanosecond, func(ctx context.Context) {
time.Sleep(time.Second)
// FAIL
})
}
type It ¶
type Message ¶
type Message string
Example ¶
package main
import (
"go.llib.dev/testcase/assert"
"testing"
)
func main() {
var tb testing.TB
assert.True(tb, true, "this is a const which is interpreted as assertion.Message")
}
type Retry ¶ added in v0.144.0
type Retry struct{ Strategy RetryStrategy }
Retry Automatically retries operations whose failure is expected under certain defined conditions. This pattern enables fault-tolerance.
A common scenario where using Retry will benefit you is testing concurrent operations. Due to the nature of async operations, one might need to wait and observe the system with multiple tries before the outcome can be seen.
Example ¶
package main
import (
"math/rand"
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
waiter := assert.Waiter{
WaitDuration: time.Millisecond,
Timeout: time.Second,
}
w := assert.Retry{Strategy: waiter}
var t *testing.T
// will attempt to wait until assertion block passes without a failing testCase result.
// The maximum time it is willing to wait is equal to the wait timeout duration.
// If the wait timeout reached, and there was no passing assertion run,
// the last failed assertion history is replied to the received testing.TB
// In this case the failure would be replied to the *testing.T.
w.Assert(t, func(it assert.It) {
if rand.Intn(1) == 0 {
it.Fatal(`boom`)
}
})
}
Example (AsContextOption) ¶
package main
import (
"testing"
"go.llib.dev/testcase"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
s := testcase.NewSpec(tb)
s.Test(`flaky`, func(t *testcase.T) {
// flaky test content here
}, testcase.Flaky(assert.RetryCount(42)))
}
Example (ByCount) ¶
package main
import (
"math/rand"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
r := assert.Retry{Strategy: assert.RetryCount(42)}
var t *testing.T
r.Assert(t, func(it assert.It) {
if rand.Intn(1) == 0 {
it.Fatal(`boom`)
}
})
}
Example (ByCustomRetryStrategy) ¶
package main
import (
"math/rand"
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
// this approach ideal if you need to deal with asynchronous systems
// where you know that if a workflow process ended already,
// there is no point in retrying anymore the assertion.
while := func(isFailed func() bool) {
for isFailed() {
// just retry while assertion is failed
// could be that assertion will be failed forever.
// Make sure the assertion is not stuck in a infinite loop.
}
}
r := assert.Retry{Strategy: assert.RetryStrategyFunc(while)}
var t *testing.T
r.Assert(t, func(it assert.It) {
if rand.Intn(1) == 0 {
it.Fatal(`boom`)
}
})
}
Example (ByTimeout) ¶
package main
import (
"math/rand"
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
r := assert.Retry{Strategy: assert.Waiter{
WaitDuration: time.Millisecond,
Timeout: time.Second,
}}
var t *testing.T
r.Assert(t, func(it assert.It) {
if rand.Intn(1) == 0 {
it.Fatal(`boom`)
}
})
}
Example (Count) ¶
package main
import (
"go.llib.dev/testcase/assert"
)
func main() {
_ = assert.Retry{Strategy: assert.RetryCount(42)}
}
func MakeRetry ¶ added in v0.144.0
Example ¶
package main
import (
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.MakeRetry(5*time.Second).Assert(tb, func(it assert.It) {
// use "it" as you would tb, but if the test fails with "it"
// then the function block will be retried until the allowed time duration, which is one minute in this case.
})
}
Example (ByCount) ¶
package main
import (
"testing"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.MakeRetry(3 /* times */).Assert(tb, func(it assert.It) {
// use "it" as you would tb, but if the test fails with "it"
// it will be retried 3 times as specified above as argument.
})
}
Example (ByTimeout) ¶
package main
import (
"testing"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
var tb testing.TB
assert.MakeRetry(time.Minute /* times */).Assert(tb, func(it assert.It) {
// use "it" as you would tb, but if the test fails with "it"
// then the function block will be retried until the allowed time duration, which is one minute in this case.
})
}
func (Retry) Assert ¶ added in v0.144.0
Assert will attempt to assert with the assertion function block multiple times until the expectations in the function body met. In case expectations are failed, it will retry the assertion block using the RetryStrategy. The last failed assertion results would be published to the received testing.TB. Calling multiple times the assertion function block content should be a safe and repeatable operation.
type RetryStrategy ¶
type RetryStrategy interface {
// While implements the retry strategy looping part.
// Depending on the outcome of the condition,
// the RetryStrategy can decide whether further iterations can be done or not
While(condition func() bool)
}
func RetryCount ¶
func RetryCount(times int) RetryStrategy
type RetryStrategyFunc ¶
type RetryStrategyFunc func(condition func() bool)
func (RetryStrategyFunc) While ¶
func (fn RetryStrategyFunc) While(condition func() bool)
type Waiter ¶
type Waiter struct {
// WaitDuration is the time how lone Waiter.Wait should wait between attempting a new retry during Waiter.While.
WaitDuration time.Duration
// Timeout is used to calculate the deadline for the Waiter.While call.
// If the retry takes longer than the Timeout, the retry will be cancelled.
Timeout time.Duration
}
Waiter is a component that waits for a time, event, or opportunity.
func (Waiter) Wait ¶
func (w Waiter) Wait()
Wait will attempt to wait a bit and leave breathing space for other goroutines to steal processing time. It will also attempt to schedule other goroutines.
Example ¶
package main
import (
"time"
"go.llib.dev/testcase/assert"
)
func main() {
w := assert.Waiter{WaitDuration: time.Millisecond}
w.Wait() // will wait 1 millisecond and attempt to schedule other go routines
}
func (Waiter) While ¶
While will wait until a condition met, or until the wait timeout. By default, if the timeout is not defined, it just attempts to execute the condition once. Calling multiple times the condition function should be a safe operation.
Example ¶
package main
import (
"math/rand"
"time"
"go.llib.dev/testcase/assert"
)
func main() {
w := assert.Waiter{
WaitDuration: time.Millisecond,
Timeout: time.Second,
}
// will attempt to wait until condition returns false.
// The maximum time it is willing to wait is equal to the wait timeout duration.
w.While(func() bool {
return rand.Intn(1) == 0
})
}