golang / mock

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

Exact matching on varargs of type interface{} #692

Open Step2Web opened 1 year ago

Step2Web commented 1 year ago

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