uber-go / mock

GoMock is a mocking framework for the Go programming language.
Apache License 2.0
1.82k stars 104 forks source link

Add a helper method for inline setup of mocks #133

Open mniak opened 6 months ago

mniak commented 6 months ago

Requested feature A helper method that would make inline construction of mocks possible.

Why the feature is needed

So the test code would look nicer

Proposed solution

Maybe something like a SETUP method in every mock, which woul receive a function that configures the mock.

Example (before):

ctrl := gomock.NewController(t)
defer ctrl.Finish()

mockReader1 := NewMockDep1(ctrl)
mockReader1.EXPECT().
    ReadSomething(gomock.Any(), gomock.Any()).
    Return("first call", nil)
mockReader1.EXPECT().
    ReadSomething(gomock.Any(), gomock.Any()).
    Return("second call", nil)
mockReader1.EXPECT().
    ReadSomething(gomock.Any(), gomock.Any()).
    Return("third call", nil)

mockWriter := NewMockDep1(ctrl)
mockWriter.EXPECT().
    WriteSomething(gomock.Any(), gomock.Any()).
    Return("first call", nil)
mockWriter.EXPECT().
    WriteSomething(gomock.Any(), gomock.Any()).
    Return("second call", nil)
mockWriter.EXPECT().
    WriteSomething(gomock.Any(), gomock.Any()).
    Return("third call", nil)

sut := NewSystemUnderTest(mockReader, mockWriter)
sut.DoAction()

Example (after):


ctrl := gomock.NewController(t)
defer ctrl.Finish()

sut := NewSystemUnderTest(
    NewMockReader(ctrl).SETUP(func (mock *MockReader) {
        mock.EXPECT().
            ReadSomething(gomock.Any(), gomock.Any()).
            Return("first call", nil)
        mock.EXPECT().
            ReadSomething(gomock.Any(), gomock.Any()).
            Return("second call", nil)
        mock.EXPECT().
            ReadSomething(gomock.Any(), gomock.Any()).
            Return("third call", nil)
    }),
    NewMockWriter(ctrl).SETUP(func (mock *MockWriter) {
        mock.EXPECT().
            WriteSomething(gomock.Any(), gomock.Any()).
            Return("first call", nil)
        mock.EXPECT().
            WriteSomething(gomock.Any(), gomock.Any()).
            Return("second call", nil)
        mock.EXPECT().
            WriteSomething(gomock.Any(), gomock.Any()).
            Return("third call", nil)
    }),
)
sut.DoAction()
r-hang commented 6 months ago

I think I understand why this could reduce some hand-written function declarations if you wanted to re-use setup functions but it think that having multiple patterns for setting up mocks (one with a setup function and one without) would make mock code less uniform and make users uncertain about which approach to use (in most cases we want to reduce nesting).

From what I can tell the generated implementation would be a methods with a pointer receiver that takes in a variable with the same reference to the receiver when ideally there is one clear variable to modify.

If this is just for inline setup, would it be better to create external wrapper functions that you could call inline?