Documentation ¶
Overview ¶
Package pers (hel...pers ... get it? Yeah, I know, I have a love/hate relationship with myself too) contains a bunch of helpers for working with hel mocks. From making a mock consistently return to matchers - they'll all be here.
Index ¶
- Constants
- func BeCalled[T Method[In, Out], In, Out any](opts ...MethodAssertOption) func(T) it.Result
- func BlockReturns(t TestingT, method Blockable) (unblock func())
- func Expect[In, Out any](seq *Sequence, mock Method[In, Out], opts ...MethodAssertOption)
- func Go[T any](t TestingT, f func() (T, error)) (<-chan T, <-chan error)
- func MethodWasCalled[T, U any](t TestingT, mock Method[T, U], opts ...MethodAssertOption)
- func MethodWasNotCalled[T, U any](t TestingT, mock Method[T, U], name string, opts ...MethodAssertOption)
- func Panic[T any](mock OutMethod[T], withValue any)
- func PersistReturn[T any](t TestingT, mock OutMethod[T], args ...any) (stop func())
- func Return[T any](mock OutMethod[T], args ...any)
- func Switch[In, Out any](seq *Sequence, mock Method[In, Out], cases ...SwitchCase[In])
- type ArgMatcher
- type Blockable
- type HaveMethodExecutedMatcher
- type Method
- type MethodAssertOption
- func DoReturn[In, Out any](fn func(In) Out) MethodAssertOption
- func Returning(vals ...any) MethodAssertOption
- func StoreArgs(targets ...any) MethodAssertOption
- func WithArgs(args ...any) MethodAssertOption
- func WithStack(frames *runtime.Frames) MethodAssertOption
- func Within(d time.Duration) MethodAssertOption
- type MockOption
- type OnparMatcher
- type OutMethod
- type Sequence
- type SwitchCase
- type TestingT
Examples ¶
Constants ¶
const Any argAny = -1
Any is a special value to tell pers to ignore the value at the position used. See the various options for how this value may be used.
As an example, you can assert only on the second argument with:
HaveMethodExecuted("Foo", WithArgs(Any, 22))
const VariadicAny variadicAny = -2
VariadicAny is a special value, similar to Any, but specifically to tell pers to allow any number of values for the variadic arguments. It must be passed in after all non-variadic arguments so that its position matches the position that variadic arguments would normally be.
This cannot be used to check some variadic arguments without checking the others - at least right now, you must either assert on all of the variadic arguments or none of them.
Variables ¶
This section is empty.
Functions ¶
func BeCalled ¶ added in v0.6.6
func BeCalled[T Method[In, Out], In, Out any](opts ...MethodAssertOption) func(T) it.Result
BeCalled is a match function for use with the git.sr.ht/~nelsam/correct family of assertion libraries. It may also be used standalone to check if a method was called without explicitly failing the test.
func BlockReturns ¶ added in v0.5.0
BlockReturns blocks a mock method from returning until the returned unblock function is called. This may be used to pause ConsistentlyReturn or just to prevent a method from returning before a test has finished checking the application state.
func Expect ¶ added in v0.6.6
func Expect[In, Out any](seq *Sequence, mock Method[In, Out], opts ...MethodAssertOption)
Expect adds an expected method call to seq.
Options which are used for concurrent code are typically ignored, since a call sequence should be constructed before executing the business logic.
Options like Within, which cause the expectation to wait for a result, will delay test completion if the time elapsed since the expectation was added is less. For example:
Expect(seq, someMethod, Within(time.Second)) time.Sleep(time.Second) // At this point, Within will no longer be used, since more than a second // has elapsed since the expectation was added.
If no Returning option is used, Expect will automatically return the zero value for each return type on the method.
func Go ¶ added in v0.6.5
Go helps perform concurrent testing. In some cases, it's useful for a test to take complete control over the flow of business logic - for example, to test how the code handles timeouts or to perform checks before allowing logic to resume.
In these cases, it's common to kick off business logic in a separate goroutine. The business logic will block each time it calls a method on a hel mock, which allows us to perform assertions while the business logic is paused, then tell it to resume by telling the mock to return.
Go is provided mainly to document this pattern; but also it helps make some of the setup simpler.
See the examples for detail.
Example ¶
var t printingT someMock := newMockSomeType(t, pers.WithTimeout(time.Second)) type someResult struct { result string n int } // equivalent code without using Go: // // results := make(chan someResult, 1) // errs := make(chan error, 1) // go func() { // res, n, err := someFunc(someMock, someArgs...) // errs <- err // results <- someResult{res, n} // }() results, errs := pers.Go(t, func() (someResult, error) { result, n, err := someFunc(someMock, "foo") return someResult{result, n}, err }) // At this point, the business logic is running in a separate goroutine. // If it calls a method on a mock, it will block waiting for a return. // Let's set up an expected method call and provide a return value. pers.MethodWasCalled(t, someMock.method.SomeMethod, pers.Within(time.Second), pers.WithArgs("foo", ""), pers.Returning("baz"), ) // Within tells the mock to give the business logic time to catch up. Then // we check the parameters that SomeMethod was called with before // returning "baz". // If we get to this point, then we know that the business logic called // SomeMethod as we expected it to, and we've returned the value we want to // the business logic. Now we can set up another check. pers.MethodWasCalled(t, someMock.method.SomeOtherMethod, pers.Within(time.Second), // even if SomeOtherMethod doesn't have return values, the mock will // block until we tell it to return. pers.Returning(), ) // Eventually, the business logic will return, and we can check those // values here. err := <-errs res := <-results if err != nil { t.Fatalf("error was non-nil: %v", err) } if res.result != "baz" { t.Fatalf("result was not baz: %v", res) } t.Logf("success")
Output: success
func MethodWasCalled ¶ added in v0.6.3
func MethodWasCalled[T, U any](t TestingT, mock Method[T, U], opts ...MethodAssertOption)
MethodWasCalled is an assertion function for asserting that a method in a hel mock was called. Options may be used as additional assertions about the arguments or to adjust the method's behavior (e.g. cause it to panic or pass along return values).
MethodWasCalled will panic if mock does not have a method matching name.
Certain options may trigger panics in other cases - see the documentation for those options for more detail.
func MethodWasNotCalled ¶ added in v0.6.4
func MethodWasNotCalled[T, U any](t TestingT, mock Method[T, U], name string, opts ...MethodAssertOption)
MethodWasNotCalled is an inverse assertion function of MethodWasCalled.
func Panic ¶ added in v0.6.0
Panic enqueues a panic on a mock method call. This panic will be enqueued after any queued returns (using Return).
Panic itself will panic if mock is not a struct with a ret.Panicker field.
func PersistReturn ¶ added in v0.7.0
PersistReturn will continue adding a given value to the channel until the test is done or the returned stop function is called, whichever happens first. When PersistReturn stops adding values to the channel(s), it will drain those channels before returning.
Mock method calls may be temporarily paused using BlockReturns, which prevents PersistReturn from returning until unblocked.
After the first call to stop (or after the test completes), calls to stop will be a no-op.
The value for mock may be either a channel or a struct full of channels (usually a return struct from a generated mock).
PersistReturn will panic if:
- args contains a different number of arguments than the number of channels on mock.
- any of the arguments passed in are not compatible to the return types of mock.
func Return ¶
Return will enqueue a normal, non-panicking return on a mock method.
Return panics if:
- the passed in mock value is not a valid mock method or output field.
- the passed in args cannot be returned on the mock field.
- the passed in mock value is already full and sending another return value would block.
func Switch ¶
func Switch[In, Out any](seq *Sequence, mock Method[In, Out], cases ...SwitchCase[In])
Switch acts like a switch statement for method calls.
The cases will be checked in order, and the first matching case will be used on each call.
Switch will panic if any cases come _after_ a default case. Since the cases are checked in order, any case after a default case cannot ever occur.
A default case is defined as:
- The actual Default() case. - A Case(HasArgs(Any, Any)) (i.e. all HasArgs params are pers.Any). - Any Case(HasArgs()) (i.e. the mock method does not take parameters).
Types ¶
type ArgMatcher ¶
type ArgMatcher[In any] struct { // contains filtered or unexported fields }
ArgMatcher is a matcher type which checks a set of expected parameters against an input struct. This is used for Switch/Case logic in method call matches.
func HasArgs ¶
func HasArgs[In any](args ...any) ArgMatcher[In]
HasArgs returns an ArgMatcher that matches against a set of values, similar to the WithArgs MethodAssertOption.
Note that this does not work with legacy variadic methods. If you're running into issues with this check on variadic method calls, try regenerating your mocks.
HasArgs(Any, Any, ...) is considered an implicit default case, since it will match any method call.
Since no cases passed in after an implicit can occur, cases after an implicit default will cause a panic.
func Matches ¶
func Matches[In any](f func(In) bool) ArgMatcher[In]
Matches returns an ArgMatcher that calls a custom function with the method call's arguments.
type HaveMethodExecutedMatcher ¶
type HaveMethodExecutedMatcher struct {
// contains filtered or unexported fields
}
HaveMethodExecutedMatcher is a matcher, intended for use with packages like github.com/poy/onpar/expect, to ensure that a method on a mock was executed.
func HaveMethodExecuted ¶
func HaveMethodExecuted(opts ...MethodAssertOption) *HaveMethodExecutedMatcher
HaveMethodExecuted returns a matcher, intended for use with packages like github.com/poy/onpar/expect, which asserts that the method referenced by name was executed. Options can modify the behavior of the matcher.
HaveMethodExecuted will panic if the mock does not have a method matching name.
The HaveMethodExecutedMatcher will panic if any of the options used don't match the target mock properly. Check the documentation on the options to get more specific information about what would cause the matcher to panic.
func (HaveMethodExecutedMatcher) Match ¶
func (m HaveMethodExecutedMatcher) Match(v any) (any, error)
Match checks the mock method value v to see if it has been called.
func (*HaveMethodExecutedMatcher) UseDiffer ¶
func (m *HaveMethodExecutedMatcher) UseDiffer(d matchers.Differ)
UseDiffer sets m to use d when showing a diff between actual and expected values.
type Method ¶ added in v0.7.0
type Method[T, U any] interface { Receiver() string Name() string Variadic() bool In() chan T InDesc() string Out() chan U OutDesc() string }
Method is a method struct, usually implemented by vegr.Method.
type MethodAssertOption ¶ added in v0.6.6
type MethodAssertOption func(callPrefs) callPrefs
MethodAssertOption is an option function for the HaveMethodExecutedMatcher.
func DoReturn ¶
func DoReturn[In, Out any](fn func(In) Out) MethodAssertOption
DoReturn allows the caller full control over the method call. It takes a function, passes the method's parameters to the function, and uses the function's return values as the method's returns.
This is most useful when the return values are based on the parameters, like (io.Writer).Write. The returned integer is a count of bytes written, and often needs to be based on the length of the byte slice passed in.
The function needs to take the parameter and return type used by the mock.
There is no guarantee about the order that options will be applied in. DoReturn may be called before or after other options.
DoReturn will panic if more than one DoReturn or Returning option are passed in together.
func Returning ¶
func Returning(vals ...any) MethodAssertOption
Returning returns a HaveMethodExecutedOption which will return the arguments on the mock's return channels after the method in question has been called. With the exception of CallSequence, Return will _not_ immediately return the values - the values will be returned after the method is called.
Returning will panic if:
- The values provided are not ConvertibleTo the mock's return types.
- The number of values provided does not match the number of return types in the mock.
- For variadic methods, the matcher will use vals[len(nonVariadicArgs(mock)):] as the variadic argument.
- More than one Returning or DoReturn option is passed in together.
func StoreArgs ¶
func StoreArgs(targets ...any) MethodAssertOption
StoreArgs returns a HaveMethodExecutedOption which stores the arguments passed to the method in the addresses provided. A nil value tells the matcher to skip the argument at that index. A value of Any is treated the same as a nil value.
To store variadic arguments, you must store the whole variadic slice. StoreArgs does not store individual variadic arguments.
StoreArgs will panic if:
- The values provided are not pointers, with the exception of Any.
- The mock's arguments are not ConvertibleTo the targets' types.
- The number of targets does not match the number of arguments in the method, including the variadic slice (if any).
Example ¶
fm := newFakeMock(printingT{}) // Queue up return values for the business logic pers.Return(fm.method.Foo, nil) // Simulate calling a method on a mock fm.Foo(42, "foobar") // Provide some addresses to store the arguments var ( arg0 int arg1 string ) m := pers.HaveMethodExecuted(pers.StoreArgs(&arg0, &arg1)) _, err := m.Match(fm.method.Foo) fmt.Println(err) fmt.Println(arg0) fmt.Println(arg1)
Output: <nil> 42 foobar
func WithArgs ¶
func WithArgs(args ...any) MethodAssertOption
WithArgs returns a MethodAssertOption which tells an assertion to only pass if the method was called with the passed in arguments.
WithArgs supports Any and VariadicAny to ignore a value that you don't want to assert on.
On variadic methods, the expected variadic arguments should be included as values in arguments to WithArgs, not as a slice. So for example, a Printf-style call would be `WithArgs("%d %s", 1, "foo")` instead of `WithArgs("%d %s", []any{1, "foo"})`.
WithArgs will panic if:
- The argument passed in is not ConvertibleTo the mock's argument type at the matching index.
- len(args) is less than the number of non-variadic arguments to the method.
- On non-variadic methods, len(args) is greater than the number of arguments.
func WithStack ¶
func WithStack(frames *runtime.Frames) MethodAssertOption
WithStack returns a HaveMethodExecutedOption which will add location data for the given caller frame to the output. This is mainly used by CallSequence to add the location of the Expect call, but CallSequence will not override the stack if this option is passed in.
func Within ¶
func Within(d time.Duration) MethodAssertOption
Within returns a MethodAssertOption which tells an assertion to wait the given duration for a method to be called. This is useful when running business logic concurrently with test logic, to allow business logic to catch up.
By default assertions expect the method to already have been called.
type MockOption ¶
MockOption is an option function which may be used to control mocks.
func WithSeq ¶
func WithSeq(seq *Sequence) MockOption
WithSeq returns a mock option that sets a *Sequence for method calls to use. This only works with a CallSequence to track expected calls.
Using a CallSequence avoids things like data races, deadlocks, and goroutines. Most tests should reach for a call sequence first, and only use concurrent testing when the use case demands it.
func WithTimeout ¶
func WithTimeout(timeout time.Duration) MockOption
WithTimeout returns a mock option that sets a timeout for method calls on a mock. This is usually useful when the business logic is running concurrently with test code.
type OnparMatcher ¶ added in v0.6.5
OnparMatcher is any matcher implementing onpar's matcher type. Some code in this package supports matching against child matchers, for example:
HaveBeenExecuted("Foo", WithArgs(matchers.HaveLen(12)))
type Sequence ¶ added in v0.6.5
type Sequence struct {
// contains filtered or unexported fields
}
Sequence is used for tracking a sequence of calls on various hel mocks. A Sequence must be constructed with CallSequence.
func CallSequence ¶ added in v0.6.5
CallSequence returns a new Sequence.
func (*Sequence) Call ¶
Call handles a method call on a mock. If s has a matching method call available, then it will return the correct values. If no matching call exists, it will mark the test as failed and return the default (zero) values for each return type.
func (*Sequence) Check ¶ added in v0.6.6
Check immediately checks that all existing assertions have occurred.
Assertions are removed when a method is called, so this just checks that there are no assertions left. This method is automatically called during test cleanup to check that all of the expected calls occurred.
Check removes all assertions so that future checks will only check new assertions.
type SwitchCase ¶
type SwitchCase[In any] struct { // contains filtered or unexported fields }
SwitchCase is a case element for a Switch call.
func Case ¶
func Case[In any](match ArgMatcher[In], then ...MethodAssertOption) SwitchCase[In]
Case takes a single option to match against a set of parameters and applies the rest of the options when the match matches.
func Default ¶
func Default[In any](then ...MethodAssertOption) SwitchCase[In]
Default returns a default case. This case will match any method call.
Since no cases passed in after a Default() can occur, cases after a Default() will cause a panic.