Ok, I changed a few things around and got my unit test working.
Probably the biggest issue was that I was using Telerik JustMock Lite to do
my Mocking. It seems to not be able to handle asynchronous WebApi calls. I
commented out all the JustMock code, wrote a dummy repository, and now the
test is working. It's a pity.
Perhaps someone could suggest another Mocking library that doesn't have
this issue? (Does Moq handle async calls?)
So the final test looks like this: (and yes, I will go back and refactor
the name...eventually)
[Fact(DisplayName = "Calling the NextQuizQuestion api returns a
question")]public async void CallingNextQuizQuestionGetsAResult()
{
//Arrange
var triviaRepository = new DummyTriviaRepository();
//Act
UnitOfWork uow = new UnitOfWork(triviaRepository);
TriviaController controller = new TriviaController(uow);
var taskResult = await controller.Get();
var result = Task.FromResult(taskResult).Result;
//Assert
Assert.IsType<OkNegotiatedContentResult<TriviaQuestion>>(result);
}
On Thu, Jul 23, 2015 at 6:27 PM, Tony Wright <[email protected]> wrote:
> I understand that point of view but that would mean that I would need two
> methods, doesn't it? One to execute synchronously and the other calling
> that one via an asynchronous mechanism.
> On 23 Jul 2015 5:53 pm, "Greg Keogh" <[email protected]> wrote:
>
>> Just as an aside ... I gave up writing async unit tests years ago. After
>> jumping through hoops I realised that testing the code synchronously proves
>> that it works, then adding async testing just tests that the .NET
>> asynchronous infrastructure works (which I expect is does!). Maybe the test
>> harnesses are better at async testing now, but I generally avoid it except
>> for rare critical or fragile async points -- *Greg K*
>>
>> On 23 July 2015 at 17:28, Cormac Long <[email protected]> wrote:
>>
>>> Hi Tony,
>>>
>>> Change the return type of your test method to Task rather than void.
>>>
>>> Cheers,
>>> Cormac
>>>
>>> On Thu, Jul 23, 2015 at 2:42 PM, Tony Wright <[email protected]> wrote:
>>>
>>>> Hi all,
>>>>
>>>> I have been trying to unit test an async call in an MVC app and I can't
>>>> quite get it right.
>>>>
>>>> The application is an MVC app written in dot net.
>>>>
>>>> I am using xUnit to test the method, and Fluent Assertions to more
>>>> naturally describe the expected outcome (BDD).
>>>>
>>>> The test case is a Quiz application.
>>>>
>>>> Here is the test:
>>>>
>>>> [Fact(DisplayName = "Calling the NextQuizQuestion api returns a
>>>> question")]
>>>> public async void CallingNextQuizQuestionGetsAResult()
>>>> {
>>>> //Arrange
>>>> string userId = "[email protected]";
>>>> var triviaRepository = Mock.Create<TriviaRepository>();
>>>> Mock.Arrange(() => triviaRepository.NextQuestionAsync(userId))
>>>> .Returns(() =>
>>>> Task.FromResult(
>>>> new TriviaQuestion
>>>> {
>>>> Title = "When was .NET first released?",
>>>> Options = (new TriviaOption[]
>>>> {
>>>> new TriviaOption {Title = "2000", IsCorrect =
>>>> false},
>>>> new TriviaOption {Title = "2001", IsCorrect =
>>>> false},
>>>> new TriviaOption {Title = "2002", IsCorrect =
>>>> true},
>>>> new TriviaOption {Title = "2003", IsCorrect =
>>>> false}
>>>> }).ToList()
>>>> })
>>>> ).MustBeCalled();
>>>>
>>>> //Act
>>>> UnitOfWork uow = new UnitOfWork(triviaRepository);
>>>> TriviaController controller = new TriviaController(uow);
>>>>
>>>> var taskResult = await controller.Get();
>>>>
>>>> var result = Task.FromResult(taskResult);
>>>>
>>>> //Assert
>>>> Assert.IsType<OkResult>(result.Result);
>>>>
>>>> }
>>>>
>>>> The controller method that I am instantiating is:
>>>>
>>>> [ResponseType(typeof(TriviaQuestion))]public async Task<IHttpActionResult>
>>>> Get()
>>>> {
>>>> var userId = User.Identity.Name;
>>>>
>>>> TriviaQuestion nextQuestion = await
>>>> unitOfWork.TriviaRepository.NextQuestionAsync(userId);
>>>>
>>>> if (nextQuestion == null)
>>>> {
>>>> return this.NotFound();
>>>> }
>>>>
>>>> return this.Ok(nextQuestion);
>>>> }
>>>>
>>>>
>>>> The test crashes on the line
>>>>
>>>> var taskResult = await controller.Get();
>>>>
>>>> due to a timeout.
>>>>
>>>> The issue here I believe is that the test is single threaded and it
>>>> never returns from the call because it doesn't have a synchronisation
>>>> context to return to.
>>>>
>>>> Does anyone know how I can get this test to work?
>>>>
>>>> Regards,
>>>> Tony
>>>>
>>>
>>>
>>