`.Verify()` on one mock complains over missing invocations on another mock
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 6.4k
- Forks
- 835
- PR merge metrics
- No merged PRs in 30d
Description
(I know this is really a kind of duplicate of #1018, but since I am not authorized to comment on the closed issue, I am communicating it here.)
We had a test that was written like below (here simplified). Essentially the same as #1018 (hence the namespace), but in this case the "extra" .Setup is there for a legitimate reason. Here written without the use of MockRepository.
Steps to Reproduce
This full console app (C#) illustrates the situation:
using Moq;
namespace Moq1018;
static class Program {
static void Main() {
// set up all
var mockOne = new Mock<IOne>(MockBehavior.Strict);
var mockTwo = new Mock<ITwo>(MockBehavior.Strict);
mockOne.Setup(x => x.GetSomething()).Returns(mockTwo.Object).Verifiable();
mockTwo.Setup(x => x.DoSomething()).Verifiable();
// make SUT
var objectToTest = new ObjectToTest(mockOne.Object);
// call first method and verify
objectToTest.FirstMethod();
mockOne.Verify();
// call second method and verify
objectToTest.SecondMethod();
mockTwo.Verify();
}
}
class ObjectToTest(IOne one) {
ITwo? _Member;
public void FirstMethod() {
_Member = one.GetSomething();
}
public void SecondMethod() {
_Member?.DoSomething();
}
}
public interface IOne {
ITwo GetSomething();
}
public interface ITwo {
void DoSomething();
}
Expected Behavior
It feels the above test (just called Main here) should complete without failure.
Actual Behavior
When control reaches mockOne.Verify(), an exception is thrown because the setup on mockTwo has not been met (yet)!
Known Workarounds
- If we change overload of
.Returnsand write.Returns(() => mockTwo.Object)instead of simply.Returns(mockTwo.Object), then it works as expected. Saw this workaround in #1018, but it feels unnatural that this change should lead to another outcome. - If we move the
mockTwo.Setupstatement several lines down, to after themockOne.Verifycall, then the code runs without issue. This may give clearer test code in some cases, but above, the author wanted to keep all setups together in a single "section" of the test method. - If we move the
mockOne.Verify()down to after the call toobjectToTest.SecondMethod(), then it works. But then we cannot really prove if it wasFirstMethod()orSecondMethod()that didGetSomething. - Maybe there is an entirely different way to write the test that I had not thought of?
Version Info
Moq 4.20.72
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the standalone console app in the issue and observe the sequence through Program.Main, ObjectToTest.FirstMethod, and ObjectToTest.SecondMethod. Then trace how Setup, Returns, and Verify handle the two mocks; done means mockOne.Verify() succeeds before the second method while mockTwo.Verify() still confirms its later invocation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- testing-qa
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100
