Testing async Methods in C# 5
Last week I promised that I'd write a blog post on using Assert.ThrowsException() to test async methods. Before I get to that, let's go over some of the other issues that come up with testing async methods. First, let's look at a test to verify that an async method works correctly:   public async Task<string> GetMessage(string user) {      return await Task.FromResult(string.Format("Hello {0}", user)); }   One test that works could be written like this:   [TestMethod] public void SimplePathTest() {     var worker = new Worker();     var answer = worker.GetMessage("unit tests").Result;     Assert.AreEqual("Hello, unit tests", answer); }   I don’t like writing tests like that.  Calling “.Result” on a task is a code smell.  The test method blocks until the result is available. That’s probably OK in a test method (more on that in future blog posts), but I’m still concerned. Developers often copy code from unit tests into production code. (I’ve done it myself when I’m learning how a library works.)  For that reason, I want my unit tests for follow the practices I would use in production code. That means I want to ‘await’ the result, not block for it. You might try reworking the test like this: [TestMethod] public async void SimplePathTest() {      var worker = new Worker();      var answer = await worker.GetMessage("unit tests");      Assert.AreEqual("Hello, unit tests", answer); }   You’ll see one of two results from this change:
  • You may see that test disappear from your list of unit tests.
  • You may run the test and find that results are not reported for any code that follows the first ‘await’.
I actually prefer the first, because you’ll quickly figure out that there’s a problem. The problem is that you have an async method that has the void return type. There’s no Task returned for the test runner to examine for any exceptions that were thrown. If your test fails and the Assert expressions throw exceptions, no code is there to receive the exception and report the test failure. If you are using MSTest, or XUnit, you can fix this problem by declaring your async tests with the Task return type: [TestMethod] public async Task SimplePathTest() { var worker = new Worker();      var answer = await worker.GetMessage("unit tests");      Assert.AreEqual("Hello, unit tests", answer); } That’s it.  Now, your async tests are using the idioms that you’d want people to use in production code. Above I mentioned that this idiom is supported for XUnit and MSTest. NUnit 2.6.2 adds this support as well.  I haven’t had the chance to work with the latest version yet. I’ll write more blog entries about NUnit support for async tests as I work with them. Next time, I’ll finally answer that comment about how to test async methods that throw exceptions with a ThrowsException<> style expression.
Created: 1/21/2013 7:38:43 PM

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.