testify: Allow dynamic returns based on arguments
C# Moq allows to return data based on call arguments.
testify/mock don’t. It’s possible to do using Run, but it’s a big mess of code.
It would be great to have something like this:
myMock.On("Load", mock.AnythingOfType("string")).ReturnFn(func (token string) (*MyObj, error) {
if isValid(token) {
return someStuff(), nil
} else {
return nil, errors.New("Oh!")
}
})
I can send a PR if someone like this idea.
About this issue
- Original URL
- State: open
- Created 8 years ago
- Reactions: 53
- Comments: 30 (3 by maintainers)
Almost any other mocking framework (even some golang ones) allows for this, what is the problem of having it also in this one?
I would like to emphasize that this type of functionality is considered by many to be bare minimum functionality. The mocking capabilities of testify would be seriously improved if this were to be implemented.
this was supported by testify already, it’s RunFn https://github.com/stretchr/testify/blob/858f37ff9bc48070cde7f2c2895dbe0db1ad9326/mock/mock.go#L67
sample code
@alexandrevicenzi looks like it’s solved here https://github.com/vektra/mockery#return-value-provider-functions
Dynamic/computed returns can be achieved without adding a new feature by doing something like this:
and then consume it in the test:
I am also stuck here, I am trying to test a function which tries to push to the queue and tries 5 times, I want the mocked queue to return error first 3 times and success just after that. how can we achieve this with current implementation?
if you want different behaviors you can have different structs, or you could have the struct take a function:
Got this working using multiple function returns:
First, declaring my mock:
Then by returning multiple returns based on the input to the functions, note the one function per return value:
This is a 4 year old issue and the original maintainers are gone. I’m happy to take a serious look at this but from a quick scan, I think I see differing problem statements and differing solution suggestions.
The main thing I think I see is people asking for dynamic return values based on the original arguments… is that assesement correct?
(I know, it’s been 4 years and it’s probably frustrating but we’re trying to get the backlog smaller and specifically cleaned up 😄 )
If you came across this post like i did, and all you need to do is change the call return after n calls, try the answer from: https://stackoverflow.com/questions/46374174/how-to-mock-for-same-input-and-different-return-values-in-a-for-loop-in-golang
Use the
Times(i int)func with the mock.Call library like so: (I put the Once to be explicit):mock.On(...).Return(...).Times(**n**)mock.On(...).Return(...).Once()Not sure if this addresses above concerns on concurrency, but i assume it would if all you care about is to return a call with x after n times, then return y after. Cheers!
For anyone who is willing to try a different mocking package to get this kind of functionality, I recently stumbled upon: https://github.com/derision-test/go-mockgen
Which perfectly fit this use case. As an added benefit, most of the developer facing API is generated in with strong types 😃.
Why this is such a big problem to implement this?
@alexandrevicenzi I’m struggling to see the use case. Why do you need some logic within that method?
If you are worried about asserting the mock is getting a valid token, you could do:
Our mocks package currently cares only about inputs and outputs, rather than building custom outputs based on your own logic. If you want to have more complex mocks, you can build them easily and even leverage this package. Here is a quick example:
yourCustomMockwill have all the methods fromyourMockthrough promotion, butLoadwill have some special logic. It has the extra bonus that you can reuse it across many tests instead of defining it within each test withmyMock.On.I see #742 was opened to address this. Seems to be blocked waiting for a review by a maintainer?