golang/mock

Exact matching on varargs of type interface{}

Step2Web opened this issue · 0 comments

Actual behaviour
Setting up a Mock with exact parameters for a method with interface{} varags, doesn't match.

I'm writing unit tests for gocql and to allow mockgen to generate mocks, I'm using the gockle library which wraps all CQL code behind interfaces.

The generated mock for Query looks like this:

func (mr *MockSessionMockRecorder) Query(arg0 interface{}, arg1 ...interface{}) *gomock.Call {

My code executes in INSERT INTO with multiple parameters

score: &SomeStruct{
  Id:        "t2_123",
  Value1:    555,
  Value2:    0,
  Timestamp: now.UnixMilli(),
},

session.Query(`INSERT INTO table1 (id, value1, value2, timestamp) VALUES (?, ?, ?, ?)`,
		someStruct.Id, someStruct.Value1, someStruct.Value2, someStruct.Timestamp).Exec()```

When setting up my mocks, I want to ensure that all parameters are correct:

sessionMock.EXPECT().Query(INSERT INTO table1 (id, value1, value2, timestamp) VALUES (?, ?, ?, ?), "t2_123", 555, 0, now).Return(queryMock).Times(1)query.EXPECT().Exec().Times(1)


However, this fails with:

--- FAIL: TestExecuteQuery/Exact_Match (0.00s)
main.go:14: Unexpected call to *main.MockSession.Query([INSERT INTO table1 (id, value1, value2, timestamp) VALUES (?, ?, ?, ?) t2_123 555 0 1675461224262]) at /src/main.go:14 because:
expected call at /src/main_test.go:51 doesn't match the argument at index 2.
Got: [555 0 1675461224262] ([]interface {})
Want: is equal to 555 (int)
controller.go:137: missing call(s) to *main.MockSession.Query(is equal to INSERT INTO table1 (id, value1, value2, timestamp) VALUES (?, ?, ?, ?) (string), is equal to t2_123 (string), is equal to 555 (int), is equal to 0 (int), is equal to 2023-02-03 21:53:44.26297212 +0000 UTC m=+0.002619383 (time.Time)) /src/main_test.go:51
controller.go:137: missing call(s) to *main.MockQuery.Exec() /src/main_test.go:52
controller.go:137: aborting test due to missing call(s)

It seems like that the varags are matched a a slice instead of individually:

Got: [555 0 1675461224262] ([]interface {})
Want: is equal to 555 (int)


Next I tried matching the remaining varargs as `[]interface{}`:

sessionMock.EXPECT().Query(INSERT INTO table1 (id, value1, value2, timestamp) VALUES (?, ?, ?, ?), []interface{}{"t2_123", 555, 0, now}).Return(queryMock).Times(1)query.EXPECT().Exec().Times(1)


However, then it fails with:

Got: [t2_123 555 0 2023-02-03 21:59:40.214 +0000 UTC] ([]interface {})
Want: is equal to [t2_123 555 0 2023-02-03 21:59:40.214 +0000 UTC] ([]interface {})

Which seems to be equal and correct, but I'm not familiar enough with go / gomock to determine if this comparison is possible.

I've put a small reproducible example together: https://github.com/Step2Web/gomock_varargs_issue

**Expected behaviour** 

I would like to setup my mocks to match all parameters exactly as they were provided to the varags:

sessionMock.EXPECT().Query(INSERT INTO table1 (id, value1, value2, timestamp) VALUES (?, ?, ?, ?), "t2_123", 555, 0, time.UnixMilli(now)).Return(queryMock).Times(1)


**To Reproduce** Steps to reproduce the behaviour

Please see: https://github.com/Step2Web/gomock_varargs_issue

**Additional Information**

-   gomock mode (reflect or source): reflect
-   gomock version or git ref: `v1.6.0`
-   golang version: 1.19