-
-
Notifications
You must be signed in to change notification settings - Fork 802
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
Verifiable vs VerifyNoOtherCalls #607
Comments
Yes, this can be unexpected, but this behaviour is by design. When I got started with Moq, it took me a long time to realise that there are actually two distinct forms of
If you want I agree that it would perhaps seem more consistent to have |
I thought the motivation for introducing I understand what you're saying about targeting the setups vs. targeting the actual calls, but this seems like an internal implementation detail that users of Moq shouldn't have to care about. Especially because both methods are called |
No, that wasn't the motivation behind The motivation was to give those people who don't like strict mocks (i.e. those who want to adhere to strict AAA-style testing without having to mix up the Arrange and Assert phases) a tool to do (some of) what strict mocks can do. Different people have different preferences when it comes to testing style, so The problem with your
I agree that there shouldn't be much of a noticeable difference between |
Those are not two different things, they are the same thing. Setup in the arrange phase is required in order to establish a return value. There's simply no way that can be avoided. Given that you have to specify the entire method call in the Setup, it seems overly painful to require duplicating the exact same signature in the assert phase, especially when something exists (namely So, we have two different ways that the test can be written, as shown in the original post. Both of them are pure Arrange, Act, Assert; Purring2 does all the asserts individually (repeating the signature for no benefit) while Purring1 uses a shortcut to say "assert those things I told you to remember during arrange". If you're only verifying void methods that don't need any Setup, then sure, use the explicit Verify, no problem. But if you have to spell it out at the start anyway, why do it twice when you can just say "remember this for later"? I can't understand how anyone could possibly argue that Purring1 is "wrong" and that Purring2 is "better". If your argument is that Verifiable isn't an arrange thing, I disagree because it is still arranging the test (just like defining a return value); it is marking something to be asserted later, not actually doing any assertions now. The assertions actually happen in the assert phase, as expected. (And if you want strict AAA, it does this "better" than a strict mock does.) Also, |
Perhaps I'm reading you incorrectly, but I am getting the strong impression that you're not really interested in what any possible argument contrary to yours would've been anyway, so I don't see much of a point in laying out such an argument.
Moq offers different things to different people. I personally lean towards the "clean AAA separation" side, where strict mocks and things like As you can probably tell, I'd prefer not to have an extended debate about what is the right way of testing and what isn't.
I think I've answered your question above. So unless there's anything else I'd like to close this issue. |
(Sorry, I didn't actually mean to press the close button already. 😱 Is there something else?) |
It's more that I haven't seen any argument to the contrary yet, and you sound dismissive of the whole thing without really saying why. Perhaps I'm missing something in what you've said, not being as familiar with the code... but in this case I wonder if perhaps you're letting your familiarity of the code internals cloud a design decision about the front-end API. It happens to the best of us. I understand that there are a list of setups and a list of actual calls, and that VerifyNoOtherCalls currently checks one and not the other. I don't understand why you seem to argue that this is a good reason to not fix this. Ok, maybe the APIs were originally created for different purposes. That doesn't change that fact that the APIs exist, and it makes sense to use them in the manner I showed in Purring1, and in my opinion it does make Purring1 a better and more readable test than Purring2. Ultimately readability of tests is paramount (below correctness). AAA is itself primarily a way to make tests more readable by giving them a consistent layout. Don't Repeat Yourself is a fundamental principle, even in tests. Added to this, the current behaviour of VerifyNoOtherCalls simply doesn't make sense. "This failed because you didn't verify the thing that you verified." Perhaps this was due to a poor choice of similar verbs for different things, but again, they exist now as is. Why not take the opportunity to make this behave more consistently? Even if you personally prefer the Purring2 style, there are other people that prefer other styles, and this seems like a legitimate bug.
This is what I am suggesting. I don't see anything that would break from this suggestion, only be improved. It would not affect anyone who writes their tests in a different way. |
@uecasm, some good points there, and I see that we are already in agreement on a couple of them. Let me ponder on this for a night or so, I'll try to reply tomorrow. 😃 |
To clarify: Given a mock with one or more setups Is this correct? |
Not quite. Calling In the example at the top, Had the call not been made, then Arguably, had the call been made twice, then either |
@uecasm You're right, the cardinality implied by As described, I don't think it's possible for
What we're asking for is the behaviour of the Moq to switch as a side-effect of using I can see some possible solutions by which we could make this work:
Let me know if you have any thoughts to these. |
@Tragedian, perhaps I am misunderstanding something, but I think this could be resolved rather neatly in a different fashion. Look at it this way:
The key point is to mark invocations as verified during the call to One thing I am not sure about is whether verification should be an atomic operation. That is, if you do a batch verification via The price for all this would be a much higher runtime cost for |
(I agree, but starting a new issue isn't necessary—this has been discussed plenty of times before. See e.g. the issues referenced in #401, which we could just reactivate. And I repeat once again that we absolutely cannot simply change the implicit default from |
@stakx To be clear, I'm not questioning how this could be implemented, just whether it's a model that makes sense. I don't feel comfortable with the sequencing required here.
What is the expected behaviour here? |
@Tragedian: Nice example. I tend towards thinking that here, it's the tester's own fault for writing a test that doesn't make too much sense—it is a test that'll likely fail no matter what, due to contradictory assertions. If there was a call to Do you think this pattern is one that people would be likely to write often? |
So what about introducing |
I don't follow. What would that new method do? (The current |
Rather than looking at the invocations and check to see if it has been explicitly verified, it could look at the invocations and verify they all match the setups, in the same way that It feels like the intended outcome of this work is to get to a place where you're asserting that the mock was used in exactly the specified fashion, like strict mocks model. To that end, we might want to look at a |
Expected behaviour is simple:
In short, this is silly test code, but it is silly in a blindingly obvious way. VerifyNoOtherCalls must obviously be the last verification that is done -- nothing else ever makes sense. |
No, that would defeat the purpose of why
This is what mocks with For folks who don't like those, I suppose calling both |
Expected usage is to use a combination of If It doesn't really make sense to use VerifyAll in the same test as VerifyNoOtherCalls. You could, and it should behave consistently with the definitions, but it's still not sensible to actually write a test that way. But VerifyAll is still useful in other tests.
Yes, but some people didn't like using that, so |
@uecasm: I agree with all you've just said. (Regarding the last paragraph, I've edited my post above while you were replying.) |
Actually, I take that back. It could make sense if every method you've Setup should be called at least once; then you don't need to mark them individually as Verifiable. (I tend to put some standard stubs in the test fixture's SetUp, so there's usually something that might not be called by some test, so I don't personally use VerifyAll much.) But again yes, VerifyNoOtherCalls must be last, and this ought to be obvious to everyone from the name alone. |
Personally, I don't like an API which requires a specific call-sequence to behave reasonably.
Where That grievance aired, I think I understand what we want to achieve here and I can create a pull request to upgrade |
"Verify No Other Calls" explicitly states that it verifies that there are no other calls, which in turn heavily implies (due to "other") that calls which are already verified are excluded, and it will only object to calls made but not verified. (Which is indeed how it behaves with explicit verify, just not previously with no-args Verify.) This also implies that anything else you wanted to verify has to be done first, because VerifyNoOtherCalls would treat it as an "other call" and error out otherwise. I don't see how that could possibly be surprising to anyone. |
@Tragedian, I never heard any complaints about the fact that you have to do
You mean, after we make this change, or before? I agree once more with @uecasm here... |
Add two tests that demonstrate how `VerifyNoOtherCalls` ought to interact with both parameterless and parameterized `Verify` methods. Currently, `VerifyNoOtherCalls` only works together with parameterized `Verify`, but not with the parameterless variant (which internally is actually very different as it targets setups, not invocations). These tests are taken from: devlooped#607
Add two tests that demonstrate how `VerifyNoOtherCalls` ought to interact with both parameterless and parameterized `Verify` methods. Currently, `VerifyNoOtherCalls` only works together with parameterized `Verify`, but not with the parameterless variant (which internally is actually very different as it targets setups, not invocations). These tests are taken from: devlooped#607
Add two tests that demonstrate how `VerifyNoOtherCalls` ought to interact with both parameterless and parameterized `Verify` methods. Currently, `VerifyNoOtherCalls` only works together with parameterized `Verify`, but not with the parameterless variant (which internally is actually very different as it targets setups, not invocations). These tests are taken from: devlooped#607
Add two tests that demonstrate how `VerifyNoOtherCalls` ought to interact with both parameterless and parameterized `Verify` methods. Currently, `VerifyNoOtherCalls` only works together with parameterized `Verify`, but not with the parameterless variant (which internally is actually very different as it targets setups, not invocations). These tests are taken from: devlooped#607
@uecasm, @Tragedian - I've just pushed Moq 4.10.0 (which includes the improvement for |
Using Moq 4.8.1 and NUnit 3.9.0, with the following code:
Purring2 passes as expected. Purring1 unexpectedly fails with:
Why doesn't
Verify()
count as having verified theVerifiable()
calls?The text was updated successfully, but these errors were encountered: