Open jacknpainter opened 4 months ago
+1 on this
I also think it's beneficial to use mock.Anything
when the return value isn't important. For instance, I have a method in the mock that returns an interface to be passed to another mock. Here’s an example:
mock1.On("Method").Return(fakeStruct)
mock2.On("Method", fakeStruct).Return(anotherSomething)
In this case, I don't care about what is returned by mock1.On("Method")
, so I believe that reusing mock.Anything
or mock.AnythingOfType
would be a great solution:
mock1.On("Method").Return(mock.Anything)
mock2.On("Method", mock.Anything).Return(anotherSomething)
I think there is a fundamental misunderstanding here of what mocks are. Let's go to your function:
func (s *Service) One(ctx context.Context) error {
if err := s.storage.BeginTxFunc(ctx, func(pgx.Tx) error{
if err := s.storage.Two(ctx, tx); err != nil {
return err
}
if err := s.storage.Three(ctx, tx); err != nil {
return err
}
}); err != nil {
return err
}
}
You have mocked out s.storage.BeginTxFunc
so the anonymous function passed into BeginTxFunc
is not being run because BeginTxFunc
has been mocked out. That is the fundamental reason why this behaves the way you see, and it's 100% expected behavior.
If you wanted the anonymous function to be run, you have to use something like RunAndReturn
and explicitly call the anonymous function that's passed as an argument. https://vektra.github.io/mockery/latest/features/#expecter-structs
As you can see, the forcing of a .Return value on m.On("BeginTxFunc") stops the test from calling the other two functions as they are nested and the function has already returned.
This is indeed not what's happening, as shown above.
As to the broader question of allowing us to not specify a return value, that's unfortunately not something I'm interested in doing. This has been asked before but it creates a further maintenance burden on me to ensure that mockery knows how to always create a zero-value return if nothing was specified (and from a code generation perspective, it's actually not easy to do that for all cases generally). While technically possible, I don't see a real benefit to it. There is a lot of value in being as explicit as possible, and explicitly telling the mock you want it to return a zero-value for your return type is a good thing IMO.
In this case, I don't care about what is returned by mock1.On("Method"), so I believe that reusing mock.Anything or mock.AnythingOfType would be a great solution:
What you're asking for is far more complicated than you might think. How is mockery supposed to know what kind of struct it should create for your returned interface? Should it be an empty struct? A stub? If you're returning an interface, why not just create a mock for it and return the mock?
If you're returning an interface, why not just create a mock for it and return the mock?
While it's possible to mock the first return, doing so adds unnecessary complexity to the test cases.
What you're asking for is far more complicated than you might think.
The mock.Anything
(from Testify) is used in the mock.On
method of my struct to indicate that the parameter does not need to be asserted. Since this constant is a string with the value mock.Anything
, it cannot simply be used in an if statement within the .Return
method to not verify the return?
Since this constant is a string with the value mock.Anything, it cannot simply be used in an if statement within the .Return method to not verify the return?
Verification of the return value doesn't happen anyway. If your mocked method gets called, mockery has to return something. It has no option. So what does it return? Well, it can return a zero-value, but what does a zero-value look like for an interface? What does that mean? The point is, this is not easy to do for the general case.
Description
Sometimes it is necessary for mocked functions to allow for not checking return values. I am currently running into an issue with mocks generated via mockery where I have to specify a
.Return
value for a mock even though the return value of that mock makes no difference to the running of the functions within the mock.Mockery Version
mockery v2.43.2
Golang Version
go 1.22.5
Installation Method
Steps to Reproduce
Define a helper function to aid with database transactions
Mock this function using mockery, which returns
Use function to do something
This is due to the return value from
BeginTxFunc
being used before either of the other two functions can be calledAs you can see, the forcing of a
.Return
value onm.On("BeginTxFunc")
stops the test from calling the other two functions as they are nested and the function has already returned. I have gotten around this problem before by not definining a.Return
value when mocking theBeginTxFunc
function, but this appears to not be possible via mockeryThe line causing me problems specifically in the generated mocks is this
Expected Behavior
An option to allow mocks without
.Return
valuesOR
An option to override the mock generation for a specific function. For this situation I have found that this works
Actual Behavior
panic: no return value specified for Xyz
ORFAIL: 1 out of N expectation(s) were met.