testx | testx/check | testx/checkconv |
testx
is a Go testing library that provides test runners to write reliable
and expressive unit tests effortlessly, with minimal boilerplate.
go get -u github.com/drykit-go/testx
testx
provides 3 types of runners:
ValueRunner
runs tests on a single value.HTTPHandlerRunner
runs tests on http handlers and middlewares.TableRunner
runs a series of test cases on a single function.
ValueRunner
runs tests on a single value.
func TestGet42(t *testing.T) {
testx.Value(Get42()).
Exp(42). // expect 42
Not(3, "hello"). // expect not 3 nor "hello"
Pass(checkconv.AssertMany( // expect to pass input checkers:
check.Int.InRange(41, 43), // expect in range [41:43]
// ...
)...).
Run(t)
}
Related examples:
HTTPHandlerRunner
runs tests on http handlers and middlewares.
It provides methods to perform checks:
- on the input request (e.g. to ensure it has been attached an expected context by some middleware)
- on the written response (status code, body, header...)
- on the execution time.
func TestHandleGetMovieByID(t *testing.T) {
r, _ := http.NewRequest("GET", "/movies/42", nil)
// Note: WithRequest can be omitted if the input request is not relevant.
// In that case it defaults to httptest.NewRequest("GET", "/", nil).
testx.HTTPHandlerFunc(HandleGetMovieByID).WithRequest(r).
Response(
check.HTTPResponse.StatusCode(check.Int.InRange(200, 299)),
check.HTTPResponse.Body(check.Bytes.Contains([]byte(`"id":42`))),
).
Duration(check.Duration.Under(10 * time.Millisecond)).
Run(t)
}
Related examples:
TableRunner
runs a series of test cases on a single function.
For monadic functions (1 parameter, 1 return value), its usage is straightforward:
func isEven(n int) { return n&1 == 0 }
func TestIsEven(t *testing.T) {
testx.Table(isEven).Cases([]testx.Case{
{In: 0, Exp: true},
{In: 1, Exp: false},
{In: -1, Exp: false},
{In: -2, Exp: true},
}).Run(t)
}
Note that TableRunner
supports any function type (any parameters number,
any return values numbers). If the tested function is non-monadic, it requires
an additional configuration to know where to inject Case.In
and which
return value to compare Case.Exp
with (see examples below)
Related examples:
All runners expose two methods to run the tests: Run
and DryRun
.
Run(t *testing.T)
runs the tests, fails t
if any check fails,
and outputs the results like standard tests:
--- FAIL: TestMyHandler (0.00s)
/my-repo/myhandler_test.go:64: response code:
exp 401
got 200
FAIL
FAIL my-repo 0.247s
FAIL
DryRun()
runs the tests, store the results and returns a Resulter
interface
to access the stored results:
// Resulter provides methods to read test results after a dry run.
type Resulter interface {
// Checks returns a slice of CheckResults listing the runned checks
Checks() []CheckResult
// Passed returns true if all checks passed.
Passed() bool
// Failed returns true if one check or more failed.
Failed() bool
// NChecks returns the number of checks.
NChecks() int
// NPassed returns the number of checks that passed.
NPassed() int
// NFailed returns the number of checks that failed.
NFailed() int
}
Related examples: