public class CarController : ApiController {
private ICarService carService;
[...]
public async Task<IEnumerable<Car>> Get() { return await this.carService.GetAllAsync(); }
}
public interface ICarService { Task<IEnumerable<Car>> GetAllAsync();
[...]
}
var carService = Substitute.For<ICarService>(); cars = new List<Car> { new Car() { Name = "Car 1", Id = 0, Description = "Car n1"}, new Car() { Name = "Car 2", Id = 1, Description = "Car n2"}, new Car() { Name = "Car 3", Id = 2, Description = "Car n3"}, new Car() { Name = "Car 4", Id = 3, Description = "Car n4"} }; carService.GetAllAsync().Returns(Task.FromResult(cars.AsEnumerable())); var subject = new CarController(carService);
Now, I'm using MSPec for the testing. I'd like to have a test that checks what happens if, in the call to the GetAllAsync method of the service, an exception is raised.
Test Name: should throw an exception
Test FullName: Controllers.API.CarControllerTests+When_I_call_get_and_the_service_throws_an_exception::should_throw_an_exception
Test Source: c:\Projects\Git\Web.Tests\Controllers\API\CarControllerTests.cs : line 62
Test Outcome: Failed
Test Duration: 0:00:00.0020001
Result Message: Can not return value of type UnwrapPromise`1 for ICarService.GetAllAsync (expected type Task`1).
Make sure you called Returns() after calling your substitute (for example: mySub.SomeMethod().Returns(value)),
and that you are not configuring other substitutes within Returns() (for example, avoid this: mySub.SomeMethod().Returns(ConfigOtherSub())).
If you substituted for a class rather than an interface, check that the call to your substitute was on a virtual/abstract member.
Return values cannot be configured for non-virtual/non-abstract members.
Correct use:
mySub.SomeMethod().Returns(returnValue);
Potentially problematic use:
mySub.SomeMethod().Returns(ConfigOtherSub());
Instead try:
var returnValue = ConfigOtherSub();
mySub.SomeMethod().Returns(returnValue);
Result StackTrace:
at NSubstitute.Core.ConfigureCall.CheckResultIsCompatibleWithCall(IReturn valueToReturn, ICallSpecification spec)
at NSubstitute.Core.ConfigureCall.SetResultForLastCall(IReturn valueToReturn, MatchArgs matchArgs)
at NSubstitute.Core.CallRouter.LastCallShouldReturn(IReturn returnValue, MatchArgs matchArgs)
at NSubstitute.Core.SubstitutionContext.LastCallShouldReturn(IReturn value, MatchArgs matchArgs)
at NSubstitute.SubstituteExtensions.Returns[T](MatchArgs matchArgs, T returnThis, T[] returnThese)
at NSubstitute.SubstituteExtensions.Returns[T](T value, T returnThis, T[] returnThese)
at Controllers.API.CarControllerTests.When_I_call_get_and_the_service_throws_an_exception.<.ctor>b__10() in c:\Projects\Git\Controllers\API\CarControllerTests.cs:line 59
Try extracting the task to a variable. What version of .NET are you using?
That is super odd, I just tried this in linqpad:
void Main()
{
var foo = Substitute.For<IFoo>();
foo.Foo().Returns(Task.Run(() => { throw new Exception(); }));
foo.Foo().Wait();
}
public interface IFoo
{
Task Foo();
}
--
You received this message because you are subscribed to a topic in the Google Groups "NSubstitute" group.
To unsubscribe from this topic, visit
https://groups.google.com/d/topic/nsubstitute/8qP8tzARtFI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
nsubstitute...@googlegroups.com.
To post to this group, send email to
nsubs...@googlegroups.com.
Visit this group at http://groups.google.com/group/nsubstitute.
For more options, visit https://groups.google.com/d/optout.
Establish context = () => { crashService = Substitute.For<ICarService>(); var test = Task.Run(() => { throw new Exception(); }); crashService.GetAllAsync().Returns(test); };
And interestingly (but annoyingly :) ), when I run the test in debug, it throws an exception at the line where I create the Task.
You can see that for a reason I don't quite get, the debugger goes into the "throw new Exception" and it crashes directly.
The exception will be thrown inside the task, and the debugger will break into the task.
Establish context = () =>
{
crashService = Substitute.For<ICarService>();
var test = Task.Run(() => { throw new Exception(); });
var test2 = test; // Set a breakpoint here, after the debugger breaks, continue, then this breakpoint should be hit. This shows that the Task.Run() method did not throw and the exception has been trapped inside the task.
crashService.GetAllAsync().Returns(test);
};
Talking about sync context, I am not a fan about the way MSpec has done its async support. When you mix sync contexts, async/await and .Wait() in the same spot you are in a very dangerous place because you can really easily deadlock your tests. But that is a much larger discussion, I have a blog post on the subject: http://jake.ginnivan.net/blog/2014/01/10/on-async-and-sync-contexts/
...<p class="MsoNormal" style="background: whit
Ah.. Yeah, that is my fault..
You need:
Task.Run<IEnumerable<Car>>(() => { throw new Exception(); });
--
private static IEnumerable<Car> ThrowsException() { throw new Exception(); }
var test = Task
.Run<IEnumerable<Protocol>>(() => ThrowsException());
crashService = Substitute.For<IProtocolService>().GetAllAsync().Return(test);
...<span style="font-size:10.0pt;font-family:Consolas;color:#2B91AF