Documentation ¶
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ExpNil expNiler = expNilerImpl{}
ExpNil is a value indicating that nil is an expected value. It is meant to be used as a Case.Exp value in a TableRunner test.
Functions ¶
This section is empty.
Types ¶
type Case ¶
type Case struct { // Lab is the label of the current case to be printed if the current // case fails. Lab string // In is the input value injected in the tested func. In interface{} // Exp is the value expected to be returned when calling the tested func. // If Case.Exp == nil (zero value), no check is added. This is a necessary // behavior if one wants to use Case.Pass or Case.Not but not Case.Exp. // To specifically check for a nil value, use ExpNil. // // testx.Table(myFunc, nil).Cases([]testx.Case{ // {In: 123, Pass: checkers}, // Exp == nil, no Exp check added // {In: 123}, // Exp == nil, no Exp check added // {In: 123, Exp: nil}, // Exp == nil, no Exp check added // {In: 123, Exp: testx.ExpNil}, // Exp == ExpNil, expect nil value // }) Exp interface{} // Not is a slice of values expected not to be returned by the tested func. Not []interface{} // Pass is a slice of check.ValueChecker that the return value of the // tested func is expected to pass. Pass []check.ValueChecker }
Case represents a Table test case. It must be provided values for Case.In, and Case.Exp or Case.Not or Case.Pass at least.
type CheckResult ¶
type CheckResult struct { // Passed is true if the current check passed Passed bool // Reason is the string output of a failed test as returned by a // check.Explainer, typically in format "exp X, got Y". Reason string // contains filtered or unexported fields }
CheckResult is a single check result after a dry run.
func (CheckResult) String ¶
func (cr CheckResult) String() string
type HTTPHandlerRunner ¶
type HTTPHandlerRunner interface { Runner // DryRun returns a HandlerResulter to access test results // without running *testing.T. DryRun() HandlerResulter // WithRequest sets the input request to call the handler with. // If not set, the following default request is used: // http.NewRequest("GET", "/", nil) WithRequest(*http.Request) HTTPHandlerRunner // Request adds checkers on the resulting request, // after the last middleware is called and before the handler is called. Request(...check.HTTPRequestChecker) HTTPHandlerRunner // Response adds checkers on the written response. Response(...check.HTTPResponseChecker) HTTPHandlerRunner // Duration adds checkers on the handler's execution time; Duration(...check.DurationChecker) HTTPHandlerRunner }
HTTPHandlerRunner provides methods to run tests on http handlers and middlewares.
func HTTPHandler ¶
func HTTPHandler( h http.Handler, middlewares ...func(http.Handler) http.Handler, ) HTTPHandlerRunner
HTTPHandler returns a HandlerRunner to run tests on http handlers and middlewares.
Example (Middlewares) ¶
package main import ( "context" "fmt" "net/http" "time" "github.com/drykit-go/testx" "github.com/drykit-go/testx/check" ) func main() { // withLongProcess middleware processes something for 100 milliseconds. withLongProcess := func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(100 * time.Millisecond) next.ServeHTTP(w, r) }) } // withContextValue middleware attaches the input key-val pair // to the request context. withContextValue := func(key, val interface{}) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := context.WithValue(r.Context(), key, val) next.ServeHTTP(w, r.WithContext(ctx)) }) } } // withContentType middleware sets the response header Content-Type // to contentType. withContentType := func(contentType string) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", contentType) next.ServeHTTP(w, r) }) } } results := testx.HTTPHandler(nil, // nil is interpreted as a no-op handler withLongProcess, withContextValue("userID", 42), withContentType("application/json"), ). Duration(check.Duration.Over(100 * time.Millisecond)). Request(check.HTTPRequest.Context(check.Context.HasKeys("userID"))). Response(check.HTTPResponse.Header(check.HTTPHeader.HasValue("application/json"))). DryRun() fmt.Println(results.Passed()) }
Output: true
func HTTPHandlerFunc ¶
func HTTPHandlerFunc( hf http.HandlerFunc, middlewareFuncs ...func(http.HandlerFunc) http.HandlerFunc, ) HTTPHandlerRunner
HTTPHandlerFunc returns a HandlerRunner to run tests on http handlers and middlewares.
Example ¶
package main import ( "net/http" "testing" "time" "github.com/drykit-go/testx" "github.com/drykit-go/testx/check" ) func MyHTTPHandler(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") if id != "42" { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } time.Sleep(500 * time.Millisecond) w.Write([]byte("ok")) } func main() { t := &testing.T{} // ignore: emulating a testing context t.Run("good request", func(t *testing.T) { r, _ := http.NewRequest("GET", "/endpoint?id=42", nil) testx.HTTPHandlerFunc(MyHTTPHandler).WithRequest(r). Response( check.HTTPResponse.StatusCode(check.Int.InRange(200, 299)), check.HTTPResponse.Body(check.Bytes.Is([]byte("ok"))), ). Run(t) }) t.Run("bad request", func(t *testing.T) { r, _ := http.NewRequest("GET", "/endpoint?id=404", nil) testx.HTTPHandlerFunc(MyHTTPHandler).WithRequest(r). Response(check.HTTPResponse.Status(check.String.Contains("Not Found"))). Duration(check.Duration.Under(10 * time.Millisecond)). Run(t) }) }
Output:
Example (DryRun) ¶
package main import ( "fmt" "net/http" "time" "github.com/drykit-go/testx" "github.com/drykit-go/testx/check" ) func MyHTTPHandler(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") if id != "42" { http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) return } time.Sleep(500 * time.Millisecond) w.Write([]byte("ok")) } func main() { handlerRunner := testx.HTTPHandlerFunc(MyHTTPHandler) goodRequest, _ := http.NewRequest("GET", "/endpoint?id=42", nil) goodRequestResults := handlerRunner.WithRequest(goodRequest). Response( check.HTTPResponse.StatusCode(check.Int.InRange(200, 299)), check.HTTPResponse.Body(check.Bytes.Is([]byte("ok"))), ). DryRun() badRequest, _ := http.NewRequest("GET", "/endpoint?id=404", nil) badRequestResults := handlerRunner.WithRequest(badRequest). Response(check.HTTPResponse.Status(check.String.Contains("Not Found"))). Duration(check.Duration.Under(10 * time.Millisecond)). DryRun() fmt.Println(goodRequestResults.Passed()) fmt.Println(goodRequestResults.ResponseStatus()) fmt.Println(badRequestResults.Passed()) fmt.Println(badRequestResults.ResponseStatus()) }
Output: true 200 OK true 404 Not Found
type HandlerResulter ¶
type HandlerResulter interface { Resulter // ResponseHeader returns the gotten response header. ResponseHeader() http.Header // ResponseStatus returns the gotten response status. ResponseStatus() string // ResponseCode returns the gotten response code. ResponseCode() int // ResponseBody returns the gotten response body. ResponseBody() []byte // ResponseDuration returns the handler's execution time. ResponseDuration() time.Duration }
HandlerResulter provides methods to read HandlerRunner results after a dry run.
type Resulter ¶
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 }
Resulter provides methods to read test results after a dry run.
type Runner ¶
type Runner interface { // Run runs a test and fails it if a check does not pass. Run(t *testing.T) }
Runner provides a method Run that runs a test.
type TableConfig ¶
type TableConfig struct { // InPos is the nth parameter in which Case.In value is injected, // starting at 0. // It is required if the tested func accepts multiple parameters. // Default is 0. InPos int // OutPos is the nth return value that is tested against Case.Exp, // starting at 0. // It is required if the tested func returns multiple values. // Default is 0. OutPos int // FixedArgs is a slice of arguments to be injected into the tested func. // Its values are fixed for all cases. // It is required if the tested func accepts multiple parameters. // // Let nparams the number of parameters of the tested func, len(FixedArgs) // must equal nparams or nparams - 1. // // The following configurations produce the same result: // // testx.Table(myFunc).Config(testx.TableConfig{ // InPos: 1 // FixedArgs: []interface{"myArg0", "myArg2"} // len(FixedArgs) == 2 // }) // // testx.Table(myFunc).Config(testx.TableConfig{ // InPos: 1 // FixedArgs: []interface{0: "myArg0", 2: "myArg2"} // len(FixedArgs) == 3 // }) FixedArgs Args }
TableConfig is configuration object for TableRunner. It allows to test functions having multiple parameters or multiple return values. Its zero value is a valid config for functions of 1 parameter and 1 return value, so it can be omitted in that case.
type TableResulter ¶
type TableResulter interface { Resulter // PassedAt returns true if the ith test case passed. PassedAt(index int) bool // FailedAt returns true if the ith test case failed. FailedAt(index int) bool // PassedLabel returns true if the test case with matching label passed. PassedLabel(label string) bool // FailedLabel returns true if the test case with matching label failed. FailedLabel(label string) bool }
TableResulter provides methods to read TableRunner results after a dry run.
type TableRunner ¶
type TableRunner interface { Runner // DryRun returns a TableResulter to access test results // without running *testing.T. DryRun() TableResulter // Config sets configures the TableRunner for functions of multiple // parameters or multiple return values. Config(cfg TableConfig) TableRunner // Cases adds test cases to be run on the tested func. Cases(cases []Case) TableRunner }
TableRunner provides methods to run a series of test cases on a single function.
func Table ¶
func Table(testedFunc interface{}) TableRunner
Table returns a TableRunner to run test cases on a func. By default, it works with funcs having a single input and output value. Use TableRunner.Config to configure it for a more complex functions.
Example (Dyadic) ¶
package main import ( "errors" "testing" "github.com/drykit-go/testx" ) func main() { t := &testing.T{} // ignore: emulating a testing context // divide is the func to be tested. // It returns x/y or a non-nil error if y == 0 divide := func(x, y float64) (float64, error) { if y == 0 { return 0, errors.New("division by 0") } return x / y, nil } // func divide has several parameters and return values, // so we specify a config to determinate: // - at which param position Case.In is injected // - the values used for the other arguments (fixed for all cases) // - which return value we want to compare Case.Exp with // // In this example, we check the error value of divide (return value // at position 1). // We inject Case.In at position 1 (param y) and use a fixed value // of 42.0 at position 0 (param x) for all cases. testx.Table(divide).Config(testx.TableConfig{ // Positions start at 0 InPos: 1, // Case.In injected in param position 1 (y) OutPos: 1, // Case.Exp compared to return value position 1 (error value) FixedArgs: []interface{}{0: 42.0}, // param 0 (x) set to 42.0 for all cases }).Cases([]testx.Case{ {In: 1.0, Exp: testx.ExpNil}, // divide(42.0, 1.0) -> (_, nil) {In: 0.0, Exp: errors.New("division by 0")}, // divide(42.0, 0.0) -> (_, err) }).Run(t) }
Output:
Example (Monadic) ¶
package main import ( "testing" "github.com/drykit-go/testx" "github.com/drykit-go/testx/check" "github.com/drykit-go/testx/checkconv" ) func main() { t := &testing.T{} // ignore: emulating a testing context // double is the func to be tested. double := func(x float64) float64 { return 2 * x } // func double has 1 parameter and 1 return value, // hence no config is needed testx.Table(double).Cases([]testx.Case{ {In: 0.0, Exp: 0.0}, {In: -2.0, Pass: checkconv.AssertMany(check.Float64.InRange(-5, -3))}, }).Run(t) }
Output:
type ValueRunner ¶
type ValueRunner interface { Runner // DryRun returns a Resulter to access test results // without running *testing.T. DryRun() Resulter // Exp adds an equality check on the tested value. Exp(value interface{}) ValueRunner // Not adds inequality checks on the tested value. Not(values ...interface{}) ValueRunner // Pass adds checkers on the tested value. Pass(checkers ...check.ValueChecker) ValueRunner }
ValueRunner provides methods to perform tests on a single value.
Example ¶
package main import ( "testing" "github.com/drykit-go/testx" "github.com/drykit-go/testx/check" "github.com/drykit-go/testx/checkconv" ) func main() { t := &testing.T{} // ignore: emulating a testing context get42 := func() int { return 42 } // Some dummy func // Run Value test via Run(t *testing.T) testx.Value(get42()). Exp(42). // pass Not(3, "hello"). // pass Pass(checkconv.Assert(check.Int.InRange(41, 43))). // pass Run(t) }
Output:
Example (DryRun) ¶
package main import ( "fmt" "github.com/drykit-go/testx" "github.com/drykit-go/testx/check" "github.com/drykit-go/testx/checkconv" ) func main() { get42 := func() int { return 42 } // Some dummy func results := testx.Value(get42()). Exp(42). // pass Pass(checkconv.AssertMany( check.Int.GTE(41), // pass check.Int.InRange(-1, 1), // fail )...). DryRun() fmt.Println(results.Passed()) fmt.Println(results.Failed()) fmt.Println(results.Checks()) fmt.Println(results.NPassed()) fmt.Println(results.NFailed()) fmt.Println(results.NChecks()) }
Output: false true [{passed} {passed} {failed value: exp in range [-1:1] got 42}] 2 1 3
func Value ¶
func Value(v interface{}) ValueRunner
Value returns a ValueRunner to run tests on a single value.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package check provides types to perform checks on values in a testing context.
|
Package check provides types to perform checks on values in a testing context. |
Package checkconv provides functions to convert typed checkers into generic ones.
|
Package checkconv provides functions to convert typed checkers into generic ones. |
cmd
|
|
internal
|
|
fmtexpl
Package fmtexpl provides functions to format failed test explanations.
|
Package fmtexpl provides functions to format failed test explanations. |