1

My solution architect and I were discussing the correct way to unit test the asynchronous code.

He prefers using void [Test] methods, and asserting Task.Result, while I feel that asynchronous methods should be tested with async/await [Test] methods.

Somehow, I feel that using Task.Result is incorrect way to testing the asynchronous code, but can't justify or pin-point exactly why?

For example, given the below code:

    public class SomeService 
    {
        public async Task<bool> ProcessSomething(string request)
        {
           return await Repository.Save(request);
        }
    }

Method 1: Task.Result

    [Test]
    public void ServiceProcessTest()
    {          
       var sut = new SomeService();

       // Use Task.Result
       var unusedResult= sut.ProcessSomething("Hello world!").Result;
       
       A.CallTo(() => Repository.Save(A<string>>.Ignored)).MustHaveHappenedOnceExactly();
    }

Method 2: async/await

    [Test]
    public async Task ServiceProcessTest()
    {          
       var sut = new SomeService();

       // Use async/await
       var unusedResult= await sut.ProcessSomething("Hello world!");
       
       A.CallTo(() => Repository.Save(A<string>>.Ignored)).MustHaveHappenedOnceExactly();
    }

Which once should we be using, and why? If both are correct, then are there times when one is preferred over the other?

Marshal
  • 6,551
  • 13
  • 55
  • 91
  • 3
    `async-await` is the documented practice, as `Task.Result` can cause deadlock – Nkosi Apr 05 '21 at 17:46
  • [Async Programming : Unit Testing Asynchronous Code](https://learn.microsoft.com/en-us/archive/msdn-magazine/2014/november/async-programming-unit-testing-asynchronous-code) – Nkosi Apr 05 '21 at 18:03
  • Reference [Async/Await - Best Practices in Asynchronous Programming](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming) – Nkosi Apr 05 '21 at 18:10
  • 2
    As with any aspect of any method, you should test it the way you use it, else your test isn't helping you verify that it will work properly in the cases you care about. If your tests are testing different behavior than your production code uses, then the tests aren't adding any value. – Servy Apr 05 '21 at 18:27
  • @Nkosi: Yes I did look at the Microsoft documentation, however it didn't deny using Task.Result (or I might have missed it). – Marshal Apr 05 '21 at 18:27
  • What @Servy said. :-) Make the choice in your production code and then echo it in your tests. – Charlie Apr 05 '21 at 19:08

1 Answers1

1

As others have pointed out in the comments, always use async/await if you can, since Task.Result can cause deadlocks. Also, the unit test should reflect how you use the System Under Test (SUT) from production code.

The only circumstance when you should use Task.Result IMO, is when introducing a function/object that returns a Task in legacy code and you aren't in the position (yet) to make the calling method async, so you are forced to use Task.Result to execute the Task.

Aage
  • 5,932
  • 2
  • 32
  • 57