Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit test for asynchronous code

I have got some code, which is using HttpWebRequest class's .BeginGetResponse() method and it is asynchronous. Also, I am using Microsoft's Unit Test App project for testing application.

The problem is that test framework does not waiting for end of running asynchronous code, so I can not check its result.

How should I test asynchronous code using Unit Test App project? I'm not using async/await modificators.

like image 750
Artem Zinnatullin Avatar asked Jun 19 '13 08:06

Artem Zinnatullin


2 Answers

Update Answer
The original answer was quite an old one, before async and await were prevalent. I'd now recommend using them, by writing something like:

[TestMethod]
public async Task RunTest()
{
    var result = await doAsyncStuff();
    // Expectations
}

There's a good article that covers this in depth Async Programming : Unit Testing Asynchronous Code

Old Answer

I would tend to something simple like using a polling loop and checking a flag that would be set in the async code or you could use reset events. A simple example using threads:

[TestMethod]
public void RunTest()
{
    ManualResetEvent done = new ManualResetEvent(false);
    Thread thread = new Thread(delegate() {
        // Do some stuff
        done.Set();
    });
    thread.Start();

    done.WaitOne();
}

You'll need to think about exceptions and use a try/finally and report the errors to do this properly, but you get the idea. This method however might not suit if you're doing lots of async stuff over and over, unless you fancy pushing this into a reusable method.

like image 160
Ian Avatar answered Nov 01 '22 06:11

Ian


You could also use async/await pattern (using the HttpWebRequest wrapper from the Microsoft.Bcl.Async nuget package). This will also neatly handle any exceptions that occur in your background thread.

For example:

[TestMethod]
public void RunTest()
{
    bool asyncDone = false;

    // this is a dummy async task - replace it with any awaitable Task<T>
    var task = Task.Factory.StartNew(() => 
    {
        // throw here to simulate bad code
        // throw new Exception();

        // Do some stuff
        asyncDone = true;
    });

    // Use Task.Wait to pause the test thread while the background code runs.
    // Any exceptions in the task will be rethrown from here.
    task.Wait();

    // check our result was as expected
    Assert.AreEqual(true, asyncDone);
}
like image 27
Paul Annetts Avatar answered Nov 01 '22 06:11

Paul Annetts