-
-
Notifications
You must be signed in to change notification settings - Fork 805
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
Verify() fails: Expected invocation on the mock once, but the invocation has been done #1055
Comments
From what you describe, I sounds likely that it is a cocurrency problem. Without a minimal reproducer, it is hard to tell! |
Hi Attached is a sample project that reflects our production code. I could not reproduce, but I could reproduce the issue again with our production code, by running the tests with R# unit test runner feature "Until failure". My question is also, if it is by-design impossible that this happens due to concurrency. Cheers |
This comment has been minimized.
This comment has been minimized.
@ysteiger, given your repro code, I cannot reproduce the test failure you're describing. @Ettores88, your issue seems unrelated to @ysteiger's. Hint, |
@ysteiger, on a closer look at your repro code, I think I can guess what's going wrong. You originally said:
Yet that is not what you're actually doing. In your tests, you are not creating the mock—you're adding setups to it. Let's randomly pick two tests from the same fixture in your repro code: [TestMethod]
public async Task LoadData1_1()
{
_serviceMock.Setup(x => x.MyProperty1).Returns("Mocked_MyProperty1_Result");
var testee = new Testee(_serviceMock.Object);
await testee.ReloadDataAsync(LoadOptions.Data1);
_serviceMock.Verify(x => x.MyProperty1, Times.Once);
_serviceMock.Verify(x => x.MyProperty2, Times.Never);
} [TestMethod]
public async Task LoadData1_2()
{
_serviceMock.Setup(x => x.MyProperty1).Returns("Mocked_MyProperty1_Result");
var testee = new Testee(_serviceMock.Object);
await testee.ReloadDataAsync(LoadOptions.Data1);
_serviceMock.Verify(x => x.MyProperty1, Times.Once);
_serviceMock.Verify(x => x.MyProperty2, Times.Never);
} Notice that both tests add an identical setup to the same mock. Because they set up the same call, one of those setups will effectively shadow the other. So what can happen is this: test 1 adds setup A, and then invokes that setup. Right after this, test 2 (which depending on your test runner's configuration may be executing concurrently) adds setup B for the same calls, and right after that, test 1 verifies that the call was made. However, that verification step no longer goes against setup A, which is now shadowed by the equivalent setup B (which however hasn't received any calls just yet). And thus verification fails in test 1. So this isn't a problem in Moq. You're sharing a mock between tests without ensuring that each test has exclusive access while it runs. If you want to test whether this theory is correct, inspect the mock once verification fails—the latest version of Moq allows you to inspect all the setups configured on a mock by querying its The solution is easy: don't share one mock between tests. Let each test instantiate its own mock, and keep a reference to it in a local variable. |
Hi, thanks for your reply. I cannot agree to your theory. In mstest, for each test the constructor is called, thus, each test should have its own instance of mock. I verified that the constructor is called for each test and that for each test the mock was setup with only the setup of the respective test. Of course we can try with local instances of mocks. |
I agree that my above theory was incorrect. However, if it's truly the case that each test has its own separate mock, then the error must be in your code... since mocks don't share any state when it comes to recording invocations and verifying setups. I've taken another look and I believe you got your async code wrong. I've noticed that you've got some delays in the methods that set your mock's properties: private Task LoadData1()
{
return Task.Factory.StartNew(() =>
{
var result = _service.MyProperty1;
Task.Delay(_random.Next(1, 300));
}
);
} However, the test appear to all pass immediately. Let me make a small change to make this even more obvious: private Task LoadData1()
{
return Task.Factory.StartNew(() =>
{
+ Task.Delay(5000);
var result = _service.MyProperty1;
- Task.Delay(_random.Next(1, 300));
}
);
} If you have everything set up correctly, the tests checking whether Which means that private Task LoadData1()
{
- return Task.Factory.StartNew(() =>
+ return Task.Factory.StartNew(async () =>
{
- Task.Delay(5000);
+ await Task.Delay(5000);
var result = _service.MyProperty1;
}
);
} And now, all of your tests fail immediately. This proves they're not actually waiting for the above started task to complete. Let's fix that, too: - private Task LoadData1()
+ private async Task LoadData1()
{
- return Task.Factory.StartNew(async () =>
- {
await Task.Delay(5000);
var result = _service.MyProperty1;
- }
);
} And now all of your tests take 5 seconds each to complete; and they should all pass because now, they're actually waiting for You should perhaps also fix the compiler warning for
by making this change: - Task.WhenAll(loadTasks.ToArray())
- .ConfigureAwait(true).GetAwaiter().GetResult();
+ await Task.WhenAll(loadTasks.ToArray()); TL;DR: You have a race condition between your |
Thanks a lot for your inspection and concise explanation |
Hi
I have a setup
serviceMock.Setup(x => x.SomeProperty).Returns(someValue)
.Later, I call
serviceMock.Verify(x => x.SomeProperty, Times.Once)
Now after a long time without failing, the test fails with:
Expected invocation on the mock once, but was 0 times:
x => x.SomeProperty
Then a list of performed invocations follows. Surprisingly, x.SomeProperty is in the list of performed invocations.
The mock is a member of the test class and is created for every test.
Is this a problem of concurrency?
We use Moq 4.13.1.
The text was updated successfully, but these errors were encountered: