-
-
Notifications
You must be signed in to change notification settings - Fork 794
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
.Callback(…)
after .Returns(…)
/ .CallBase()
causes a variety of issues
#668
Comments
@kzu: I would recommend that we deprecate after-returns callbacks, i.e. the following setup pattern: mock.Setup(m => m.GetMessage()).Returns("Blah.").Callback(…);
// ^^^^^^^^^^^^
// Let's make `Callback` illegal after `Returns` (or `CallBase`). This pattern doesn't make sense due to the reason I gave in the previous post. TL;DR: In a regular method, anything after What's your opinion on this? Would this be an option for Moq v5 or v6? |
I do think it's useful to be able to do a callback after a returns or a throws. This will be an option in v5. That said, introducing a new Further restricting the Alternatively, a Roslyn analyzer that flags the pattern as an error could do too ;). |
Thanks for the feedback! 👍 Since Moq 5 will allow such callbacks we should then keep them in Moq 4. |
Closing this for now. Might reconsider this for the next release; if we have other binary breaking changes in there, we could include the closed PR (linked above) there. |
Moq has allowed a
.Callback(…)
to occur after.Returns(…)
or.CallBase()
for a while now. This was originally discussed in this discussion on Google Groups and then formally requested in Google Code issue 19.Unfortunately, the way after-return callbacks are currently implemented in the fluent API, they cause a variety of issues:
.Throws()
is specified too #667: Fluent API allows setting up a second callback that won't get involved if.Throws()
is specified tooThese issues result largely from the fluent API interface
ICallback
being reused inappropriately, instead of introducing a dedicated and more limitedICallbackAfterReturn
.It can be argued that the ability of configuring a callback after
.Returns(…)
or.CallBase()
is fundamentally wrong, since in regular methods everything after areturn
statement would be unreachable. The order of theCallback
,CallBase
,Raises
,Returns
,Throws
verbs in a Moq setup generally represents the order in which these steps will be executed at runtime, so in analogy to regular methods, one could expect that.Returns(…)
should be the final verb.Here are few options (there may be more) how to fix this:
Rename the after-return
Callback
verb toFinally
:This would be a breaking change for two reasons: (1) Different method name. (2) Different semantics: A
finally
gets invoked even in the presence of an exception. An after-return callback currently won't get invoked if an exception happens beforehand.Fix the fluent API so
.Returns(…)
and.CallBase()
return an interface that doesn't inheritICallback
, but a newICallbackAfterReturns
interface instead which has more limited "flow" options. This could fix the issues linked above (at the cost of quite a bit of additional internal code duplication), but it doesn't even address the more fundamental issue.Don't fix the problems linked above. Instead, deprecate after-return
Callback
and possibly remove this facility in Moq v5 or v6.The text was updated successfully, but these errors were encountered: