Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How can I retire mock.On condition to allow mock to match later mock.On? #1375

Open
egolearner opened this issue Apr 14, 2023 · 2 comments
Open
Labels
pkg-mock Any issues related to Mock question Questions related to API usage

Comments

@egolearner
Copy link

egolearner commented Apr 14, 2023

My interface is like this

type Meta interface {
	MultiPut(ctx context.Context, keys []string, values []string) error
}

We use mockery to generate the following mocks

// Meta is an autogenerated mock type for the Meta type
type Meta struct {
	mock.Mock
}

// MultiPut provides a mock function with given fields: ctx, keys, values
func (_m *Meta) MultiPut(ctx context.Context, keys []string, values []string) error {
	ret := _m.Called(ctx, keys, values)

	var r0 error
	if rf, ok := ret.Get(0).(func(context.Context, []string, []string) error); ok {
		r0 = rf(ctx, keys, values)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

I have multiple mock.On with mock.MatchedBy. As the function is called multiple times, I want later function call is matched by later mock.On

		It("use matched by", func() {
			keys1 := make([]string, 1)
			keys1[0] = "called 0"
			keys2 := make([]string, 2)
			keys2[0] = "called 1"
			keys2[1] = "called 2"
			values := make([]string, 1)
			meta.On("MultiPut", mock.Anything, mock.MatchedBy(func(keys []string) bool {
				Expect(len(keys)).To(Equal(1))
				Expect(keys[0]).To(Equal("called 0"))
				return true
			}), mock.Anything).Once().Return(nil)
			Expect(meta.MultiPut(context.Background(), keys1, values)).To(BeNil())

			meta.On("MultiPut", mock.Anything, mock.MatchedBy(func(keys []string) bool {
				Expect(len(keys)).To(Equal(2))
				Expect(keys[0]).To(Equal("called 1"))
				Expect(keys[1]).To(Equal("called 2"))
				return true
			}), mock.Anything).Return(nil)
			Expect(meta.MultiPut(context.Background(), keys2, values)).To(BeNil())
		})

However, I got the following error. Clearly the first mock.On is used against the second function call.

 [FAILED] Expected
      <int>: 2
  to equal
      <int>: 1
  In [It] at: test.go

One work around is to build the exact arguments instead of using mock.MatchedBy

		It("use direct value", func() {
			keys1 := make([]string, 1)
			keys1[0] = "called 0"
			keys1Dup := make([]string, len(keys1))
			copy(keys1Dup, keys1)
			keys2 := make([]string, 2)
			keys2[0] = "called 1"
			keys2[1] = "called 2"
			keys2Dup := make([]string, len(keys2))
			copy(keys2Dup, keys2)
			values := make([]string, 1)
			meta.On("MultiPut", mock.Anything, keys1Dup, mock.Anything).Return(nil)
			Expect(meta.MultiPut(context.Background(), keys1, values)).To(BeNil())

			meta.On("MultiPut", mock.Anything, keys2Dup, mock.Anything).Return(nil)
			Expect(meta.MultiPut(context.Background(), keys2, values)).To(BeNil())
		})

However, in some scenarios, exact arguments can be complicated to build or we may only want to match some parts of a Struct. Is it possible to retire a previous mock.On match so that later mock.On will be matched against?

I also tried to use call.Once, it does not seem to work

			meta.On("MultiPut", mock.Anything, mock.MatchedBy(func(keys []string) bool {
				Expect(len(keys)).To(Equal(1))
				Expect(keys[0]).To(Equal("1"))
				return true
			}), mock.Anything).Once().Return(nil)

Thanks for any guidance.

@egolearner
Copy link
Author

related issue #456

@dolmen dolmen added question Questions related to API usage pkg-mock Any issues related to Mock labels Jul 5, 2023
@tscales
Copy link
Contributor

tscales commented Aug 31, 2023

I attempted to reproduce this locally with a modification to Test_Mock_OnWithSliceArgMatcher in mock_test.go.

func Test_Mock_On_WithSliceArgMatcher(t *testing.T) {
	var mockedService TestExampleImplementation

	mockedService.On("TheExampleMethod7",
		MatchedBy(func(slice []bool) bool { return slice == nil }),
	).Once().Return(errors.New("fixture1"))

	mockedService.On("TheExampleMethod7",
		MatchedBy(func(slice []bool) bool {
			if slice[0] != true {
				return false
			}
			return len(slice) == 2
		})).Return(errors.New("fixture2"))

	assert.EqualError(t, mockedService.TheExampleMethod7(nil), "fixture1")
	assert.EqualError(t, mockedService.TheExampleMethod7([]bool{true, true}), "fixture2")
}

The test succeeded. It may be an issue with Ginko rather than testify.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg-mock Any issues related to Mock question Questions related to API usage
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants