Ariel Larsen
Ariel Larsen

Reputation: 53

How to unit test a synchronous method calling asynchronous method?

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

Answers (2)

Stephen Cleary
Stephen Cleary

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

Richard Otvos
Richard Otvos

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

Related Questions