testcase is an opinionated testing framework to support test driven design.
Align the AnyOf
assertion helper with other existing assertion helper functions in the assert package.
The new approach should be idiomatic with the rest of the assert package and more convenient.
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)
})
})
Introduce a random.Unique
utility function to simplify the generation of unique random values in tests,
reducing the risk of flaky test results where an assertion expects district values from two randomly made input
rnd := random.New(random.CryptoSeed{})
v1 := rnd.Int()
v2 := random.Unique(rnd.Int, v1)
v3 := random.Unique(rnd.Int, v1, v2)
assert.AnyOf -> assert.A
To fix your codebase, run the following shell script (GNU coreutils)
find . -type f -name "*.go" -exec sed -i'' -e 's/assert\.AnyOf)/assert.A)/g' {} \;
go.llib.dev/testcase
Transition to our updated import path go.llib.dev/testcase
.
Previously, it was through github.com, but now it's streamlined to go.llib.dev/testcase
. This change allows for more adaptability regarding where we store our source code, be it on my personal GitHub account or within a GitHub organization.
assert.Eventually
The assertion retry helper has undergone a name change:
assert.Eventually -> assert.Retry
assert.EventuallyWithin -> assert.MakeRetry
The function assert.Eventually
has now become a top-tier test assisting function, enabling easier creation of 'eventually' assertions similar to our other helper functions.
Hello, testing enthusiasts! 🚀
We've got some important news to share based on the invaluable feedback from our community. There's been a common misstep in how some of our users have been utilizing assertion functions with testcase, and we've taken steps to address it.
The Issue:
Several of you have been inadvertently using assertion functions meant for a single parameter with two parameters. A typical example we've seen:
assert.Error(t, expectedErr, actualErr, "expectation message")
This isn't ideal because the third argument for these functions isn't for comparison but is a variadic assertion message argument. In such cases, expectedErr
gets checked as an error, and actualErr
is interpreted as a failure assertion message.
Our Solution:
We've updated the function's signature to mitigate this and ensure clarity in function usage. It now mandates a string-based type for assertion failure messages. This change ensures that the compiler will flag any type mismatches, making it much more challenging to misuse the function.
We're confident that this update will streamline your testing experience and reduce inadvertent errors. We recommend updating your testcase/assert
library to the latest version to leverage this enhancement.
Your feedback drives our improvements, and we're grateful for your continued support and insights. Please don't hesitate to reach out with any questions, concerns, or further feedback.
Happy coding, and thank you for being an integral part of our community! 🚀
httpspec
random.Random
Happy testing!
upgrade testcase to the latest
defer faultinject.Enable()()
ctx := context.Background()
// all fault field is optional.
// in case left as zero value,
// it will match every caller context,
// and returns on the first .Err() / .Value(faultinject.Fault{})
ctx = faultinject.Inject(ctx, faultinject.CallerFault{
Package: "targetpkg",
Receiver: "*myreceiver",
Function: "myfunction",
}, errors.New("boom"))
// from and after call stack reached: targetpkg.(*myreceiver).myfunction
if err := ctx.Err(); err != nil {
fmt.Println(err) // in the position defined by the Fault, it will yield an error
}
rnd := random.New(rand.NewSource(time.Now().Unix()))
p := make([]byte, 42)
n, err := rnd.Read(p)
_, _ = n, err
rnd := random.New(rand.NewSource(time.Now().Unix()))
err := rnd.Error()
_ = err
var v = testcase.Var[int]{
ID: "myvar",
Init: func(t *testcase.T) int { return 42 },
Before: func(t *testcase.T, v testcase.Var[int]) {
t.Logf(`I'm from the Var.Before block, and the value: %#v`, v.Get(t))
},
}
var tb testing.TB = &testcase.StubTB{}
outcome := testcase.Sandbox(func() {
// some test helper function calls fatal, which cause runtime.Goexit after marking the test failed.
tb.FailNow()
})
fmt.Println("The sandbox run has finished without an issue", outcome.OK)
fmt.Println("runtime.Goexit was called:", outcome.Goexit)
fmt.Println("panic value:", outcome.PanicValue)
var tb testing.TB
assert.NoError(tb, nil) // passes
assert.NoError(tb, errors.New("boom")) // fails
stub := &testcase.StubTB{}
stub.Log("hello", "world")
fmt.Println(stub.Logs.String())
rnd := random.New(rand.NewSource(time.Now().Unix()))
rnd.StringNWithCharset(42, random.Charset())
rnd.StringNWithCharset(42, random.CharsetASCII())
rnd.StringNWithCharset(42, random.CharsetAlpha())
rnd.StringNWithCharset(42, "ABC")
rnd := random.New(rand.NewSource(time.Now().Unix()))
rnd.StringNC(42, random.Charset())
myHandlerWithFaultInjectionMiddleware := fihttp.Handler{
Next: myHandler,
ServiceName: "our-service-name",
FaultsMapping: fihttp.FaultsMapping{
"mapped-fault-name": func(ctx context.Context) context.Context {
return faultinject.Inject(ctx, FaultTag{}, errors.New("boom"))
},
},
}
Add package level assertion functions to testcase/assert
package
This will make the assert package align with other popular assertion packages in terms of conventions.
Examples:
Add testcase.T.SkipUntil
that is equivalent to Log followed by SkipNow if the test is executing prior to the given deadline time.
SkipUntil is useful when you need to skip something temporarily, but you don't trust your memory enough to return to it on your own.
assert.Asserter.Equal
and other assertions that test equality will respect the .IsEqual
method on the value.
When it does a comparison and .IsEqual
is defined, it will use that instead of deep equality checking.
If a value has unexported values or a stateful field that requires a delicate way to compare, through this method, it becomes possible.
httpspec
is extended with a RoundTripperMiddleware
contract.
You can verify common scenarios with your round-tripper middleware using the shared spec. This shared contract should allow you to focus on the round-trippers business logic rather than the generic middleware behaviour.