Golang: how to mock ...interface{} arguents using gomock

5.1k views Asked by At

I have a Printer interface that uses the standard go Printf function signature:

type Printer interface {
    Printf(format string, tokens ...interface{})
}

I would like to be able to mock this interface using gomock, but I'm not sure how setup the tokens ...interface{} argument properly.

I expected that Printf(gomock.Any(), gomock.Any()) would cover all potential cases (since tokens compiles to []interface{}), but it appears you need to setup an explicit call for N number of tokens:

// no tokens
mockPrinter.EXPECT().
    Printf(gomock.Any()).
    AnyTimes()

// 1 token
mockPrinter.EXPECT().
    Printf(gomock.Any(), gomock.Any()).
    AnyTimes()

// 2 tokens
mockPrinter.EXPECT().
    Printf(gomock.Any(), gomock.Any(), gomock.Any()).
    AnyTimes()

// ... up to N tokens

Does anyone know of a better way to do this?

2

There are 2 answers

0
Denzel On

Not possible with the current version of gomock. Maybe you can extend it, and send a pull request in. To understand why it's not possible, you have to look at the mock generated for variadic functions.

To do that, let's look at the examples in gomock's repository, specifically ./sample/mock_user/user.go and ./sample/mock_user/mock_user.go.

Generated Mock

You'll see a function in the Index inteface called Ellip, which is like your Printf function:

type Index interface {
    // ...
    Ellip(fmt string, args ...interface{})
    // ...
}

Now, here's what the mocked function looks like for Ellip:

func (_m *MockIndex) Ellip(_param0 string, _param1 ...interface{}) {
    _s := []interface{}{_param0}
    for _, _x := range _param1 {
        _s = append(_s, _x)
    }
    _m.ctrl.Call(_m, "Ellip", _s...)
}

Notice anything odd? Well, gomock is creating a slice of interfaces, _s, initialized with the first parameter. Then it appends the variadic parameters to that slice of interfaces, _s.

So, to be clear, it doesn't just append the variadic parameter, _param1, to the slice. Each individual variadic from _param1 is appended to the new slice, by iterating through it.

This means that the slice of variadic parameters is not preserved. It's broken out.

0
Greg Owen On

As of October 1, 2017, gomock.Any() works correctly for variadic args: https://github.com/golang/mock/pull/101