diff --git a/README.md b/README.md index 1b84036..cbbac2c 100644 --- a/README.md +++ b/README.md @@ -93,9 +93,10 @@ func TestUnit(t *testing.T) { Run(func(t test.Test, param UnitParams){ // Given - mocks := mock.NewMock(t).Expect( - param.mockSetup, - ) + mocks := mock.NewMock(t). + SetArg("common-url", "http://test").Expect( + param.mockSetup, + ) unit := NewUnitService( mock.Get(mocks, NewServiceMock), diff --git a/mock/README.md b/mock/README.md index 2a31a87..03e0c8d 100644 --- a/mock/README.md +++ b/mock/README.md @@ -22,6 +22,7 @@ func TestUnit(t *testing.T) { mocks := mock.NewMocks(t) mockSetup := mock.Get(mocks, NewServiceMock).EXPECT()... + mocks.Expect(mockSetup) service := NewUnitService( @@ -85,11 +86,16 @@ prepared to handle tests with detached *goroutines*, i.e. functions that are spawned by the system-under-test without waiting for their result. The mock handler therefore provides a `WaitGroup` and automatically registers -a single mock call on each request using `mocks.Do(...)` and notifies the +a single mock call on each request using `mocks.Do(...)` to notify the call completion via `Do|DoAndReturn()`. For test with detached *goroutines* the test can wait via `mocks.Wait()`, before finishing and checking whether the mock calls are completely consumed. +Since some arguments needed to setup a mock call may only be available after +creating the test runner, the mock controller provides a dynamic key-value +storage that is accessible via `SetArg(key,value)`, `SetArgs(map[key]value)`, +and `GetArg(key)`. + **Note:** Since waiting for mock calls can take literally for ever in case of test failures, it is advised to use an isolated [test environment](../test) that unlocks the waiting test in case of failures and fatal errors, e.g. diff --git a/mock/mock.go b/mock/mock.go index 3f2d898..4bab79c 100644 --- a/mock/mock.go +++ b/mock/mock.go @@ -81,6 +81,8 @@ type Mocks struct { wg sync.WaitGroup // The map of mock singletons. mocks map[reflect.Value]any + // A map of mock key value pairs. + args map[any]any } // NewMocks creates a new mock handler using given test reporter, e.g. @@ -90,6 +92,7 @@ func NewMocks(t gomock.TestReporter) *Mocks { Ctrl: gomock.NewController(t), wg: sync.NewLenientWaitGroup(), mocks: map[reflect.Value]any{}, + args: map[any]any{}, }).syncWith(t) } @@ -116,6 +119,28 @@ func (mocks *Mocks) Expect(fncalls SetupFunc) *Mocks { return mocks } +// GetArg gets the mock argument value for the given argument key. This can be +// used to access a common test arguments from a mock call. +func (mocks *Mocks) GetArg(key any) any { + return mocks.args[key] +} + +// SetArg sets the given mock argument value for the given argument key. This +// can be used to pass a common test arguments to mock calls. +func (mocks *Mocks) SetArg(key any, value any) *Mocks { + mocks.args[key] = value + return mocks +} + +// SetArgs sets the given mock argument values for the given argument keys. +// This can be used to pass a set of common test arguments to mock calls. +func (mocks *Mocks) SetArgs(args map[any]any) *Mocks { + for key, value := range args { + mocks.args[key] = value + } + return mocks +} + // syncWith used to synchronize the wait group of the mock setup with the wait // group of the given test reporter. This function is called automatically on // mock creation and therefore does not need to be called on the same reporter diff --git a/mock/mock_test.go b/mock/mock_test.go index db128e2..0b1e159 100644 --- a/mock/mock_test.go +++ b/mock/mock_test.go @@ -187,6 +187,28 @@ func TestMocks(t *testing.T) { }) } +func TestMockArgs(t *testing.T) { + // Given + mocks := mock.NewMocks(t) + + // When + mocks.SetArg("a", "a") + + // Than + assert.Equal(t, mocks.GetArg("a"), "a") + assert.Equal(t, mocks.GetArg("b"), nil) + + // When + mocks.SetArgs(map[any]any{ + "a": "b", + "b": "b", + }) + + // Than + assert.Equal(t, mocks.GetArg("a"), "b") + assert.Equal(t, mocks.GetArg("b"), "b") +} + func MockSetup(t gomock.TestReporter, mockSetup mock.SetupFunc) *mock.Mocks { return mock.NewMocks(t).Expect(mockSetup) }