-
-
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
Usage of ReturnsExtensions.ThrowsAsync() can cause UnobservedTaskException #592
Comments
Hi @snrnats. Thanks for reporting. I'll try to look into this during the next few days! Right now, my best first guess is that in this line (and other similar ones): we might instead have to use a lambda ( |
@snrnats - TL;DR: Would you like to submit a PR to fix this problem? You can find instructions on how to do so below. Cause of this problem:My above guess was on the right track. This issue is indeed caused by the faulted task not getting created only on demand / in a lazy fashion. Here's what the var tcs = new TaskCompletionSource<bool>();
tcs.SetException(exception);
return mock.Returns(tcs.Task); Let's try to access var tcs = new TaskCompletionSource<bool>();
tcs.SetException(exception);
return mock.Returns(() =>
{
return tcs.Task;
}); That won't help. Seems that var tcs = new TaskCompletionSource<bool>();
return mock.Returns(() =>
{
tcs.SetException(exception);
return tcs.Task;
}); This fixes the problem you've reported! Since we've gone that far already, there's no point in creating return mock.Returns(() =>
{
var tcs = new TaskCompletionSource<bool>();
tcs.SetException(exception);
return tcs.Task;
}); If you'd like to submit a PR for fixing this:
If I don't hear from you in the next 10 days or so, I'll apply the above fix. Thank you! :-) P.S.:The fix I've described above has one side effect: whereas until now, var task = new Lazy<Task>(() =>
{
var tcs = new TaskCompletionSource<bool>();
tcs.SetException(exception);
return tcs.Task;
});
return mock.Returns(() => task.Value); |
Hi @stakx thank you for clarifying the root of the problem Here are my thoughts about Lazy implementation. In real applications both scenarios are possible, that method returns a new task or the same task. For now we should keep the original behavior that returns the same task. In future I would create a parameter to allow different behavior if somebody requested it. |
It appears that |
@snrnats - I think it'd be good to also fix I can think of only one thing (and it's only a vague feeling; I haven't thought it through at this point, so it might not even be necessary at all): There might be some cases where Like I said, this might not be necessary, but perhaps keep this in mind. |
Oops, this got accidentally closed due to the "resolve" keyword in #594's description:
Reopening... @snrnats, good work so far. Thank you! 👍 |
@snrnats - I'm reviewing your PR right now, and while it looks solid—I have only a few minor change requests—, it has made me realise that it might be good to think a little bit longer about consistency: What's the difference between If we wanted good consistency, wouldn't this distinction be transferable to To be honest, it's entirely possible that this would take consistency too far and that most people just wouldn't intuitively understand these fine distinctions; and, like you say, this API might simply not be implementable for the method overloads that allow you to specify a delay. So while I think it's probably better to keep the API simple (as it is now, without the |
Here are my thoughts about async:
In both cases we are getting a new task each time we call the method. On the other side, sometimes we reuse the task. I am aware of at least one case when we want to mimic the behavior that keeps returning the same task:
I think that this case should be mocked in a way when you explicitly say to use the same task. Then it will mimic the same behavior as in the implementation details. It can be achieved by using regular |
Usage of ReturnsExtensions.ThrowsAsync() will cause UnobservedTaskException if:
Scenario where it can cause troubles is when you want to check that your code doesn't throw any UnobservedExceptions. It will looks like this
Sample project MoqThrowsAsync.zip or code:
The text was updated successfully, but these errors were encountered: