Reputation: 53
What is the correct way to write a unit test for a synchronous method calling async methods. Right now my unit test are passing, but when I try to open the page, it never returns. Why isn't my unit test failing? How can I make it fail?
I replicated my problem with this simple code:
My passing test:
[TestMethod]
public void DoSomeWork_WhenWeDoSomeWork_ShouldReturnDone()
{
var service = new SyncService();
const string expected = "Done";
var actual = service.DoSomeWork();
Assert.AreEqual(expected, actual);
}
My view that never returns:
public ActionResult Index()
{
var syncService = new SyncService();
return View((object)syncService.DoSomeWork());
}
My service that never returns to view:
public class SyncService
{
public string DoSomeWork()
{
return SomeWork().GetAwaiter().GetResult();
}
private async Task<string> SomeWork()
{
var task1 = Task.Delay(1000);
var task2 = Task.Delay(1000);
await Task.WhenAll(task1, task2);
return "Done";
}
}
Upvotes: 5
Views: 1982
Reputation: 456352
First, don't block on async code (link to my blog). By blocking on async
code, you're actually causing a deadlock. This deadlock does not happen in your unit test because unit tests run in a thread pool context, not an ASP.NET context (link to my blog).
There are good reasons for not having synchronous wrappers for asynchronous methods. So I recommend getting rid of DoSomeWork
completely, leaving only SomeWork
(renamed to SomeWorkAsync
).
To solve your problem, you should use asynchronous controller actions.
Upvotes: 1
Reputation: 196
I don't think I can help you with this specific example, but I think a good general strategy is to write two tests. One to test if the synchronous method passes the correct data and an other to test if the asynchronous method works properly.
I mostly work in JavaScript and that general approach works for me. Also you can check the documentation of your testing frameworks, maybe it provides some methods for this.
Upvotes: 1