The problem is described here in comments under the answer: https://stackoverflow.com/questions/38338906/nsubstitute-mock-throwing-an-exception-in-method-returning-task
The problem with this is that the exception is thrown at the wrong time.
var t = AsyncMethod(); (actual behavior: exception will be raised here)
await t; (expected behavior: exception will be raised here)
With an async method the exception should be thrown when awaiting the task, Current approach throws the exception immediately.
Current behavior little bit unexpected in some cases. It would be great to correct it. Or may there is more elegant way to solve the problem.
Hi @a-l-e-x-e-y ,
Thanks for raising this issue. I think this answer is correct: we need to use Task.FromException to wrap an exception in a task and return that.
For why this is necessary, consider these two implementations of AsyncMethod:
public interface IExample {
Task<string> AsyncMethod(bool fail);
}
public class Example : IExample {
public async Task<string> AsyncMethod(bool fail) {
if (fail) throw new NotImplementedException();
// do async stuff
return "hi";
}
}
public class OtherExample : IExample {
public Task<string> AsyncMethod(bool fail) {
if (fail) throw new NotImplementedException();
return Task.Run(() => {
// do async stuff
return "hi";
});
}
}
Both throwing synchronously and throwing asynchronously both meet the required contracts, so we have to support both.
To make this easier, how would you feel about adding ThrowsAsync() to NSubstitute.ExceptionExtensions to make this approach easier?
It could mirror the existing Throws overloads, starting with:
public static ConfiguredCall ThrowsAsync(this Task value, Exception ex) {
// return using `Task.FromException`
}
Hi @dtchepak ,
Thank you for detailed explanation.
I understand the problem. And I agree that it would be more convenient and easier to use something like ThrowAsync () in this case. I planned to suggest the same variant.
@a-l-e-x-e-y Would you have time to send a PR through with this change?
If not let me know and I'll add it when I can. 馃槂
ThrowsAsync looks like a great addition to the library! Don't forget to also add overloads for ValueTask we support everywhere 馃槈
@dtchepak Ok. I'll find time for this.
@zvirja Thank you for reminder.
Most helpful comment
ThrowsAsynclooks like a great addition to the library! Don't forget to also add overloads forValueTaskwe support everywhere 馃槈