Understand how asynchrony works in .Net and adhere to the recommended practices when writing unit tests to test asynchronous code A proper and planned approach toward unit testing helps you to detect errors in your application and ensures that the application is error free. As such, unit testing has become a fundamental skill that a developer should have. Essentially, unit testing is used to test blocks or units of code to check if it conforms to the desired results. Unit testing asynchronous code is a bit tricky — you should be extra careful when unit testing asynchronous code in your application. Unit testing asynchronous code Unit testing helps to detect bugs and reduce time to market. Now, as I said earlier, unit testing asynchronous code has a few challenges that you should be aware of. Consider the following piece of code: public class IDGTest { public static async Task SampleTestMethodAsync() { await Task.Delay(100); //Some other code } } Now suppose you write the following unit test method to test the piece of code given above: [TestMethod] public void WrongApproachTest() { IDGTest.SampleTestMethodAsync(); } Unfortunately, this unit test method will always pass irrespective of whether the test fails or not. Let’s understand this better — here’s an updated version of the async method we are writing our unit test for: public static async Task SampleTestMethodAsync() { await Task.Delay(100); throw new Exception("An error occurred."); } Note the usage of the await keyword. The async and await keywords are used to implement asynchrony in applications that leverage the latest versions of the .Net Framework. The “await” keyword is used to denote a suspension point — it captures the current SynchronizationContext and as soon as the task that has been awaited using the “await” keyword is complete, the state machine is resumed and execution of the code in the caller method restarts. If you run the unit test method again, it will still pass. Why? The asynchronous method under test returns a Task object. It should be noted that when you are unit testing an asynchronous method, you should observe the Task object it returns. To do this, you should await the Task object being returned from the SampleTestMethodAsync method. Here’s the updated unit test method that takes advantage of await to call the asynchronous method: [TestMethod] public void WrongApproachTest() { await IDGTest.SampleTestMethodAsync(); } Another point you should be aware of is avoiding async void unit tests. It is quite difficult to retrieve the result of async void unit tests and hence they should be avoided. Unlike async void unit tests that are quite complicated, you can have async Task unit tests, i.e., unit tests that return a Task instance. Almost all the unit test frameworks (MSTest, NUnit, etc.) provide support for such unit tests. An async method returns control quickly and usually returns a Task that completes its execution at a future point in time. When an exception occurs inside an asynchronous method that has a return type of Task or Task, the exception details are stored inside the Task instance. Consider the following unit test method: [TestMethod] [ExpectedException(typeof(DivideByZeroException))] public void DivideNumberTest() { Task<int> task = IDGSample.Divide(10, 0); task.Wait(); } The IDGSample class is given below. This is a static class with just one static method that returns a Task instance: public static class IDGSample { public static async Task<int> Divide(int x, int y) { await Task.Delay(100); return x / y; } } In this example, the Task class would wrap exception into an instance of AggregateException. You should not use Task.Wait and Task.Result the way this example illustrates. To unwrap the exception, we should await the Task. Here’s the updated version of the unit test method — this time we have specified the async keyword in the method signature of the unit test method: [TestMethod] [ExpectedException(typeof(DivideByZeroException))] public async Task DivideNumberTestAsync() { int x = await IDGSample.Divide(10, 0); } When you execute this unit test, it would provide you the desired results. The await keyword makes the difference. Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos