Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / testing

Looking Across the Void When Doing Integration Testing of Asynchronous Functions

0.00/5 (No votes)
14 Jul 2015CPOL2 min read 9.6K  
Looking across the void when doing Integration Testing of Asynchronous Functions

The Void - That's where your test results have gone

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:

C#
public class Foo
{
    public async Task GetAStringFromIO()
    {
        // This is, presumably, a task that will take some time, so
        // we're going to await it.
        return await GetTheString();
    }

    private static Task GetTheString()
    {
        return Task.Run(() =>
        {
            // Simulate some really slow IO
            Thread.Sleep(1000);
            return "A String";
        });
    }
}

…and to test that, I wrote something along these lines:

C#
[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.

TestExplorer When Running Function returning void
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:

TestExplorerWithTask

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)