testcase is an opinionated testing framework to support test driven design.
The new StubTB allows testing test-helpers functions with a StubTB
that behaves like the testing.TB
.
This should allow reusing them as commonly used testcase.Var(s) in specs focusing on HTTP coverage.
*testcase.T.Random.String
from now on will return generic SQL and NoSQL injection strings as well.The Big List of Naughty Strings is incorporated into the testcase's random generator. Unit tests that use these randomly generated string values will double as an enhanced fuzzing test.
To run your unit tests with various naughty strings, use the -count
testing flag.
Each test execution by -count
will run with a different naughty string.
go test -count 1024 -run TestMyUnit
Assertions now support ErrorIs
assertion where you can check both if the error is equal to an expected one, or part of the actual error's error chain.
This leaves room for later refactoring like wrapping the error value to give better context to the returned error, without breaking a test.
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
Both testcase#Retry.Assert and testcase#T.Eventually use the same signature for convenience.
waiter := testcase.Waiter{
WaitDuration: time.Millisecond,
WaitTimeout: time.Second,
}
r := testcase.Retry{Strategy: waiter}
r.Assert(t, func(it assert.It) { // <- assert.It is passed here instead of testing.TB
if rand.Intn(1) == 0 {
it.Fatal(`boom`)
}
})
Exclude the time it takes to construct a dependency from the benchmark time.
func Benchmark_myBench(b *testing.B) {
s := testcase.NewSpec(b)
v := testcase.Let(s, func(t *testcase.T) int {
// benchmark time is not tracked here
time.Sleep(time.Second / 2)
return t.Random.Int()
})
s.Test(``, func(t *testcase.T) {
// benchmark time is tracked here
time.Sleep(time.Second)
_ = v.Get(t)
})
}
testcase's API is updated to remove the need for boilerplate when working with test bounded variables.
previous version had to rely on empty interface casting:
s := testcase.NewSpec(t)
input := testcase.Var{ID: "input"}
subject := func(t *testcase.T) string {
return MyFunc(input.Get(t).(string))
}
The latest release uses type safety through generics:
s := testcase.NewSpec(t)
input := testcase.Var[string]{ID: "input"}
subject := func(t *testcase.T) string {
return MyFunc(input.Get(t))
}
Happy Coding/Specifying! :)
Contract meant to represent a Role Interface Contract. A role interface is a static code contract that expresses behavioral expectations as a set of method signatures. A role interface used by one or many consumers. These consumers often use implicit assumptions about how methods of the role interface behave. Using these assumptions makes it possible to simplify the consumer code. In testcase convention, instead of relying on implicit assumptions, the developer should create an explicit interface testing suite, in other words, a Contract. The code that supplies a role interface then able to import a role interface Contract, and confirm if the expected behavior is fulfilled by the implementation.
further references:
Race is a test helper that allows you to create a race situation easily.
This is useful when you work on a component that requires thread-safety.
By using the Race helper, you can write an example use of your component,
and run the testing suite with go test -race
.
The race detector then should be able to notice issues with your implementation.
T.Random is a random generator that uses the Spec seed. When a test fails with random input from Random generator, the failed test scenario can be recreated simply by providing the same TESTCASE_SEED as you can read from the console output of the failed test.
testcase.Var.Get
and testcase.Var.Set
now thread-safe.