The Void – That’s where your test results have gone
Recently, I have been writing integration tests that cover async functions. During this work, I have encountered a quirky pain (of my own making) that I wanted to document. The purpose of the documentation is two-fold. First, the shame and self-deprecation of calling myself out will help to reinforce this point in my mind, and second, you might be able to avoid this goof up yourself.
The spoiler and 5 second take-away: When writing any function that uses async in C#, you must NEVER return void
. The async
keyword means that you intend to return something upon which the caller will await. That’s it. Lesson over.
If you want to know how weird things can get if you do this wrong in integration testing, read on…
So, I wrote a function that asynchronously returns a Task
of string
. Something like this:
public class Foo
{
public async Task GetAStringFromIO()
{
return await GetTheString();
}
private static Task GetTheString()
{
return Task.Run(() =>
{
Thread.Sleep(1000);
return "A String";
});
}
}
…and to test that, I wrote something along these lines:
[TestClass]
public class MyTests
{
[TestMethod]
public async void CanGetTheStringFromIO()
{
var foo = new Foo();
string myString = null;
myString = await foo.GetAStringFromIO();
Assert.IsNotNull(myString);
}
}
To my annoyance and great dismay, the test didn’t seem to run and my breakpoint wasn’t hit. The test wasn’t shown in the TestExplorer
window. No bueno.
The problem here, quite obviously, is that the async
test function is returning void
. The test runner expects something back on which it can await, but I am giving it nothing. This causes the test runner to exit. I wish it were more obvious, but there is no success, error, or inconclusive result – just a Test Explorer window without my test function.
After correcting the test by simply changing the return type to Task
, life is good again. The Test Explorer shows my test and I can set breakpoints which actually pause execution of the test:
Again, when writing any function that uses async
in C#, you must NEVER return void
. The async
keyword means that you intend to return something upon which the caller will await. It’s just that easy.
If you are interested in a deep dive on this topic, I would recommend that you check out this article by Stephen Cleary: http://msdn.microsoft.com/en-us/magazine/dn818493.aspx. He has published books, articles, and blog posts surrounding all things C# asynchronous programming.
CodeProject