Documentation ¶
Overview ¶
Package gounit is an augmentation of the go testing framework for test driven development. It comes with a few types to implement test suites and compact assertion to systematically remove noise from tests. It also comes with a command "gounit" which watches the source directory in which it was executed given it is in the directory structure of a go module. The gounit command
- lets you browse all tests of watched directory and nested packages.
- reruns a package's tests on modification.
- follows automatically failing tests.
- reports test-names in a human friendly manner
- suite-tests are reported in the order they are written.
- provides handy switches to turn go vet, the race detector or source-code statistics on and off.
From the gounit package you will mainly use the types gounit.Suite and gounit.T (gounit.S for Init and Finalize) as well as the function gounit.Run:
import github.com/slukits/gounit type TestedSubject struct{ gounit.Suite } func (s *TestedSubject) Should_have_tested_behavior(t *gounit.T) { // test implementation } func TestTestedSubject(t *testing.T) { gounit.Run(&TestedSubject{}, t) }
If all tests of a suite should run concurrently:
func (s *TestedSubject) SetUp(t *gounit.T) { t.Parallel() }
Note that gounit also reports normal go-tests and go-tests with sub-tests. While on the other hand suite tests are also executed using the "go test" command. A suit test is a method of a gounit.Suite-embedder which is public, not special, and has exactly one argument (which then must be of type *gounit.T but this is not validated, i.e. gounit will panic if not). Special methods are Init, SetUp, TearDown and Finalize as well as Get, Set and Del. The first four methods behave as you expect: Init and Finalize are executed before respectively after all suite-tests. SetUp and TearDown are executed before respectively after each suite-test. The other three methods are considered special because they are implemented by the Fixtures utility and it turned out to be a quite natural use case to embedded the Fixtures-type next to the Suite type in a test suite. Special methods along with compact assertions provided by gounit.T allow you in a systematic way to remove noise from your tests with the goal to make your suite-test implementations the specification of your production API. While suite tests reported in the order they were written will outline the behavior of your production code and the thought process which led there.
NOTE:
func (s *TestedSubject) Init(t *gounit.S) { // initialize your fixtures environment } func (s *TestedSubject) Should_have_tested_behavior(t *gounit.T) { // test implementation } func (s *TestedSubject) Finalize(t *gounit.S) { // tear down your fixtures environment }
Init and Finalize have not *gounit.T but *gounit.S as argument type. gounit.S wraps the test runner's testing.T instance while gounit.T wraps a test runner's sub-test testing.T instance created to run a particular suite test. A typical full-blown test suite (in pseudo-code) might look like this:
type testedSubject struct{ gounit.Suite gounit.Fixtures fixtureOriginal *myFixture } func (s *testedSubject) Init(t *gounit.S) { s.fixtureOriginal = myInMemoryFixtureGenerator() } func (s *testedSubject) SetUp(t *gounit.T) { t.Parallel() s.Set(t, s.fixtureOriginal.ConcurrencySaveClone()) } func (s *testedSubject) TearDown(t *gounit.T) { s.Del(t).(*myFixture).CleanUp() } func (s *testedSubject) fx(t *gounit.T) *myFixture { return s.Get(t).(*myFixture) } func (s *testedSubject) Has_tested_behavior(t *gounit.T) { fx := s.fx(t) // do something within the test specific fixated environment // and assert the effect of this doing. } func (s *testedSubject) Finalize(t *gounit.S) { s.fixtureOriginal.CleanUp() } func TestTestedSubject(t *testing.T) { t.Parallel() Run(&testedSubject{}, t) }
Index ¶
- Constants
- func Run(suite SuiteEmbedder, t *testing.T)
- type Fixtures
- type Not
- func (n Not) Contains(value StringRepresentation, sub string) bool
- func (n Not) Eq(a, b interface{}) bool
- func (n Not) Matched(value StringRepresentation, regex string) bool
- func (n Not) SpaceMatched(value StringRepresentation, ss ...string) bool
- func (n Not) StarMatched(value StringRepresentation, ss ...string) bool
- func (n Not) True(value bool) bool
- type S
- type StringRepresentation
- type Suite
- type SuiteCanceler
- type SuiteEmbedder
- type SuiteErrorer
- type SuiteLogger
- type T
- func (t T) Contains(value StringRepresentation, sub string) bool
- func (t T) Eq(a, b interface{}) bool
- func (t T) Err(err interface{}) bool
- func (t T) ErrIs(err interface{}, target error) bool
- func (t T) ErrMatched(err interface{}, re string) bool
- func (t T) Error(args ...interface{})
- func (t T) Errorf(format string, args ...interface{})
- func (t *T) FS() *tfs.FS
- func (t *T) FailNow()
- func (t T) Fatal(args ...interface{})
- func (t T) FatalIfNot(assertion bool)
- func (t T) FatalOn(err error)
- func (t T) Fatalf(format string, args ...interface{})
- func (t T) GoT() *testing.T
- func (t T) Log(args ...interface{})
- func (t T) Logf(format string, args ...interface{})
- func (t T) Matched(value StringRepresentation, regex string) bool
- func (t *T) Mock() *TMock
- func (t T) Panics(f func()) (hasPanicked bool)
- func (t T) Parallel()
- func (t T) SpaceMatched(value StringRepresentation, ss ...string) bool
- func (t T) StarMatched(value StringRepresentation, ss ...string) bool
- func (t T) TODO() bool
- func (t T) Timeout(d time.Duration) chan struct{}
- func (t T) True(value bool) bool
- func (t T) Within(d *TimeStepper, cond func() bool) (fulfilled bool)
- type TMock
- type TimeStepper
Constants ¶
const FinalPrefix = "__final__"
FinalPrefix prefixes logging-messages of the Finalize-method to enable the reporter to discriminate Finalize-logs and Init-logs.
const InitPrefix = "__init__"
InitPrefix prefixes logging-messages of the Init-method to enable the reporter to discriminate Init-logs and Finalize-logs.
Variables ¶
This section is empty.
Functions ¶
func Run ¶
func Run(suite SuiteEmbedder, t *testing.T)
Run sets up embedded Suite-instance and runs all methods of given test-suite embedder which are public, have exactly one argument and are not special:
- Init(*gounit.S): run before any other method of a suite
- SetUp(*gounit.T): run before every suite-test
- TearDown(*gounit.T): run after every suite-test
- Finalize(*gounit.S): run after any other method of a suite
- Get, Set, Del as methods of gounit.Fixtures are also considered special for the use case that Fixtures is embedded in a Suite-embedder (i.e. test-suite)
Types ¶
type Fixtures ¶
type Fixtures struct {
// contains filtered or unexported fields
}
Fixtures provides a simple concurrency save fixture storage for gounit tests. A Fixtures instance must not be copied after its first use. A Fixtures storage is typically used to setup test specific fixtures for concurrently run suite-tests
type MySuite { gounit.Suite fx ff } type ff { gounit.Fixtures } func (fx *ff) Of(t *gounit.T) string { return fx.Get(t).(string) } func (s *MySuite) SetUp(t *gounit.T) { t.Parallel() s.fx.Set(t, fmt.Sprintf("%p's fixture", t)) } func (s *MySuite) MySuiteTest(t *gounit.T) { t.Logf("%p: got: %s", t, s.fx.Of(t)) } func TestMySuite(t *testing.T) { t.Parallel() Run(&MySuite{}, t) }
func (*Fixtures) Del ¶
Del removes the mapping of given test to its fixture and returns the fixture.
type Not ¶
type Not struct {
// contains filtered or unexported fields
}
Not implements negations of T-assertions, e.g. Not.True. Negated assertions can be accessed through T's Not field.
func (Not) Contains ¶
func (n Not) Contains(value StringRepresentation, sub string) bool
Contains negation passes if called T.Contains assertion with given arguments fails; otherwise it fails.
func (Not) Eq ¶
Eq negation passes if called T.Eq assertion with given arguments fails; otherwise it fails.
func (Not) Matched ¶
func (n Not) Matched(value StringRepresentation, regex string) bool
Matched negation passes if called T.Matched assertion with given arguments fails; otherwise it fails.
func (Not) SpaceMatched ¶
func (n Not) SpaceMatched(value StringRepresentation, ss ...string) bool
SpaceMatched negation passes if called T.SpaceMatched assertion with given arguments fails; otherwise it fails.
func (Not) StarMatched ¶
func (n Not) StarMatched(value StringRepresentation, ss ...string) bool
StarMatched passes if called T.StarMatched assertion with given arguments fails; otherwise it fails.
type S ¶
type S struct {
// contains filtered or unexported fields
}
S instances are passed from gounit into a test-suite's Init or Finalize method, i.e. it is the "T"-instance of an Init/Finalize special method:
type MySuite { gounit.Suite } func (s *MySuite) Init(t *gounit.S) { t.Log("init called") } func (s *MySuite) MyTest(t *gounit.T) { t.Log("my test executed") } func (s *MySuite) Finalize(t *gounit.S) { t.Log("finalize called") } func TestMySuite(t *testing.T) { gounit.Run(&MySuite{}, t) }
An S instance provides logging-mechanisms and the possibility to cancel a suite's test-run. Note implementations of [SuiteLogging] or SuiteCanceler in a test-suite replace the default logging or cancellation behavior of an S-instance. NOTE an S-instance wraps the suite runner's testing.T instance while a T-instance wraps a suite runner's sub-test testing.T instance created for a particular suite test.
func (*S) FS ¶
FS returns an FS-instance with handy features for file system operations for testing. I.e. copying a "golden" test file from a packages "testdata" directory to a test specific temporary directory looks like this:
t.FS().Data().CopyFl(golden, t.FS().Temp())
It also removes error handling for file system operations by simply failing the test in case of an error.
func (S) Fatal ¶
func (st S) Fatal(args ...interface{})
Fatal cancels the test-suite's test-run after given arguments were logged. The cancellation defaults to a FailNow call of wrapped test-runner's testing.T-instance which is superseded by an optional SuiteCanceler-implementation.
func (S) FatalOn ¶
FatalOn cancels the test-suite's test-run iff given error is not nil. The cancellation defaults to a FailNow call of wrapped test-runner's testing.T-instance which is superseded by an optional SuiteCanceler-implementation.
func (S) Fatalf ¶
Fatalf cancels the test-suite's test-run after given arguments were logged. The cancellation defaults to a FailNow call of wrapped test-runner's testing.T-instance which is superseded by an optional SuiteCanceler-implementation.
type StringRepresentation ¶
type StringRepresentation interface{}
StringRepresentation documents what a string representation of any type is:
- the string if it is of type string,
- the return value of String if the Stringer interface is implemented,
- fmt.Sprintf("%v", value) in all other cases.
type Suite ¶
type Suite struct {
// contains filtered or unexported fields
}
Suite implements the private methods of the SuiteEmbedder interface. I.e. if you want to run the tests of your own test-suite using Run you must embed this type, e.g.:
type MySuite struct { gounit.Suite } // optional Init-method func (s *MySuite) Init(t *gounit.S) { //... } // optional SetUp-method func (s *MySuite) SetUp(t *gounit.T) { //... } // optional TearDown-method func (s *MySuite) TearDown(t *gounit.T) { //... } // ... the suite-tests as public methods of *MySuite ... func (s *MySuite) MyTest(t *gounit.T) { //... } // optional Finalize-method func (s *MySuite) Finalize(t *gounit.S) { //... } func TestMySuite(t *testing.T) { gounit.Run(&MySuite{}, t) }
type SuiteCanceler ¶
type SuiteCanceler interface {
Cancel() func()
}
SuiteCanceler overwrites default test-cancellation handling which defaults to a testing.T.FailNow-call of a wrapped testing.T-instance. I.e. calling on a gounit.T instance t methods like T.Fatal, T.Fatalf, T.FailNow, T.FatalIfNot, or T.FatalOn end up in an FailNow-call of the testing.T-instance which is wrapped by t. If a suite implements the SuiteCanceler-interface provided function is called in case of an test-cancellation.
type SuiteEmbedder ¶
type SuiteEmbedder interface {
// contains filtered or unexported methods
}
SuiteEmbedder is automatically implemented by embedding a Suite-instance. I.e.:
type MySuite struct{ gounit.Suite }
implements the SuiteEmbedder-interface's private methods.
type SuiteErrorer ¶
type SuiteErrorer interface {
Error() func(...interface{})
}
SuiteErrorer overwrites default test-error handling which defaults to a testing.T.Error-call of a wrapped testing.T-instance. I.e. calling on a gounit.T instance t methods like T.Error or T.Errorf end up in an Error-call of the testing.T-instance which is wrapped by t. If a suite implements the SuiteErrorer-interface provided function is called in case of an test-error.
type SuiteLogger ¶
type SuiteLogger interface {
Logger() func(args ...interface{})
}
SuiteLogger implementation of a suite-embedder replaces the default logging mechanism of gounit.T-instances E.g.:
type MySuite { gounit.Suite Logs string } func (s *MySuite) Logger() func(...interface{}) { return func(args ...interface{}) { s.Logs += fmt.Sprint(args...) } } func (s *MySuite) A_test(t *gounit.T) { t.Log("A_test has run") } func TestMySuite(t *testing.T) { testSuite := &MySuite{} gounit.Run(testSuite, t) t.Log(testSuite.Logs) // prints "A_test has run" if verbose }
type T ¶
type T struct { // Not provides negations of T-assertions like Contains or StarMatched. Not Not // contains filtered or unexported fields }
T instances are passed to suite tests providing means for logging, assertion, failing, cancellation and concurrency-control for a test:
type MySuite { gounit.Suite } func (s *MySuite) A_test(t *gounit.T) { t.Log("A_test run") } func TestMySuite(t *testing.T) { gounit.Run(&MySuite{}, t)}
func (T) Contains ¶
func (t T) Contains(value StringRepresentation, sub string) bool
Contains fails the test and returns false iff given value's string representation doesn't contain given sub-string; otherwise true is returned.
func (T) Eq ¶
Eq errors with an corresponding diff if possible and returns false if given values are not considered equal; otherwise true is returned. a and b are considered equal if they are of the same type or one of them is string while the other one is a Stringer implementation and
- a == b in case of two pointers
- a == b in case of two strings
- a.String() == b.String() in case of Stringer implementations
- a == b.Stringer() or a.Stringer() == b in case of string and Stringer implementation.
- fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b) in other cases
if they are not of the same type or one of the above cases replacing "==" by "!=" is true then given values are considered not equal.
func (T) Err ¶
Err fails the test and returns false iff given value doesn't implement the error-interface; otherwise true is returned.
func (T) ErrIs ¶
ErrIs fails the test and returns false iff given err doesn't implement the error-interface or doesn't wrap given target; otherwise true is returned.
func (T) ErrMatched ¶
ErrMatched fails the test and returns false iff given err doesn't implement the error-interface or its message isn't matched by given regex; otherwise true is returned.
func (T) Error ¶
func (t T) Error(args ...interface{})
Error logs given arguments and flags test as failed but continues its execution. t's errorer defaults to a Error-call of a wrapped testing.T instance and may be overwritten for a test-suite by implementing SuiteErrorer or leveraging T.Mock.
func (T) Errorf ¶
Errorf logs given format-string leveraging fmt.Sprintf and flags test as failed but continues its execution. t's errorer defaults to a Error-call of a wrapped testing.T instance and may be overwritten for a test-suite by implementing SuiteErrorer or leveraging T.Mock.
func (*T) FS ¶
FS returns an FS-instance with handy features for file system operations for testing. I.e. copying a "golden" test file from a package's "testdata" directory to a test specific temporary directory looks like this:
t.FS().Data().FileCopy(golden, t.FS().Temp())
It also removes error handling for file system operations by simply failing the test in case of an error.
func (*T) FailNow ¶
func (t *T) FailNow()
FailNow cancels the execution of the test after a potential tear-down was called. t's canceler defaults to a FailNow-call of a wrapped testing.T instance and may be overwritten for a test-suite by implementing SuiteCanceler or leveraging T.Mock.
func (T) Fatal ¶
func (t T) Fatal(args ...interface{})
Fatal logs given arguments and cancels the test execution (see T.FailNow).
func (T) FatalIfNot ¶
FatalIfNot cancels the test execution (see T.FailNow) if passed argument is false and is a no-op otherwise.
func (T) FatalOn ¶
FatalOn cancels the test execution (see T.FailNow) after logging given error message iff passed argument is not nil and is a no-op otherwise.
func (T) Fatalf ¶
Fatalf logs given format-string leveraging fmt.Sprintf and cancels the test execution (see T.FailNow).
func (T) GoT ¶
GoT returns a pointer to wrapped testing.T instance which usually was created by the testing.T-runner of the suite-runner's testing.T instance.
func (T) Log ¶
func (t T) Log(args ...interface{})
Log writes given arguments to set logger which defaults to the logger of wrapped testing.T instance. The default is superseded by a suite-embedder implementing the SuiteLogger interface or by leveraging T.Mock.
func (T) Logf ¶
Logf writes given format string to set logger which defaults to the logger of wrapped testing.T instance. The default is superseded by a suite-embedder implementing the SuiteLogger interface or by leveraging T.Mock.
func (T) Matched ¶
func (t T) Matched(value StringRepresentation, regex string) bool
Matched fails the test and returns false iff given values string interpretation isn't matched by given regex; otherwise true is returned.
func (T) Panics ¶
Panics fails the test and returns false iff given function doesn't panic; otherwise true is returned.
func (T) Parallel ¶
func (t T) Parallel()
Parallel signals that this test may be run in parallel with other parallel flagged tests.
func (T) SpaceMatched ¶
func (t T) SpaceMatched(value StringRepresentation, ss ...string) bool
SpaceMatched escapes given variadic strings before it joins them with the `\s*`-separator and matches the result against given value's string representation, e.g.:
<p> some text </p>
would be matched by
t.SpaceMatched(value, "<p>", "some text", "</p>").
SpaceMatched fails the test and returns false iff the matching fails; otherwise true is returned.
func (T) StarMatched ¶
func (t T) StarMatched(value StringRepresentation, ss ...string) bool
StarMatched escapes given variadic-strings before it joins them with the `.*?`-separator and matches the result against given value's string representation, e.g.:
<p> some text </p>
would be matched by
t.StarMatch(str, "p", "me", "x", "/p").
StarMatched fails the test and returns false iff the matching fails; otherwise true is returned.
func (T) Timeout ¶
Timeout returns a channel which is closed after given duration has elapsed. Is given duration 0 it defaults to 10ms.
type TMock ¶
type TMock struct {
// contains filtered or unexported fields
}
A TMock instance is obtained by T.Mock and provides the possibilities to mock logging, error handing and canceling of a test which default to testing.T.Log, testing.T.Error and testing.T.FailNow.
func (*TMock) Canceler ¶
func (m *TMock) Canceler(c func())
Canceler the last function call of an error canceling function like Fatal which by default reports back to the go testing framework to stop the test execution instantly ... if mocked the later is prevented.
func (*TMock) Errorer ¶
func (m *TMock) Errorer(e func(...interface{}))
Errorer the last function call of an error reporting function which by default reports back to the go testing framework indicating the failing of the test ... if mocked the later is prevented.
type TimeStepper ¶
type TimeStepper struct {
// contains filtered or unexported fields
}
TimeStepper provides the features to split a duration into segments. The duration defaults to 10 milliseconds segmented into 1 millisecond steps. The zero value is ready to use.
func (*TimeStepper) AddStep ¶
func (t *TimeStepper) AddStep() bool
AddStep adds an other step to the elapsed time and returns true if there is still time left; false otherwise.
func (*TimeStepper) Duration ¶
func (t *TimeStepper) Duration() time.Duration
Duration is the overall duration a time-stepper represents defaulting to 10 milliseconds.
func (*TimeStepper) SetDuration ¶
func (t *TimeStepper) SetDuration(d time.Duration) *TimeStepper
SetDuration sets the overall duration a time-stepper represents.
func (*TimeStepper) SetStep ¶
func (t *TimeStepper) SetStep(s time.Duration) *TimeStepper
SetStep sets the duration of a segment of a time-stepper's the overall duration.
func (*TimeStepper) Step ¶
func (t *TimeStepper) Step() time.Duration
Step is the step-segment of a time-stepper's overall duration defaulting to 1 millisecond.
Directories ¶
Path | Synopsis |
---|---|
cmd
|
|
gounit
Gounit watches package directories of a go module and reports test results on source file changes.
|
Gounit watches package directories of a go module and reports test results on source file changes. |
gounit/controller
Package controller starts gounit's event loop and connects the model with the view by feeding requested information extracted from watched sources to the view.
|
Package controller starts gounit's event loop and connects the model with the view by feeding requested information extracted from watched sources to the view. |
gounit/model
Package Model allows its client to watch a go source folder for changes of its testing packages.
|
Package Model allows its client to watch a go source folder for changes of its testing packages. |
gounit/view
Package view utilizes the github.com/slukits/lines package to provide gounit's terminal user interface.
|
Package view utilizes the github.com/slukits/lines package to provide gounit's terminal user interface. |
pkg
|
|
tfs
Package tfs provides complex filesystem operations for testing.
|
Package tfs provides complex filesystem operations for testing. |