9

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.

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
Artem Zinnatullin
  • 4,305
  • 1
  • 29
  • 43
  • 1
    have you thoguht about using mocks for the web class/methods? – omer schleifer Jun 19 '13 at 08:15
  • Unit testing other .Net specific code atleast like HttpWebRequest class may not sound good. Because you are just unit testing your module , thinking that what if the other module return valid value , invalid value and throw expcetion. So it would be better if you could mock the HttpWebRequest and just test your logic. – srsyogesh Jun 19 '13 at 08:15
  • Yep, I am using mocks: server returns JSON to me, so I use mocks JSONs for passing it to the parsing module. But now I need to add queries caching to my API implementation, so I need to check how it's working without debugging each time. – Artem Zinnatullin Jun 19 '13 at 08:18
  • If your test requires outsides resources like a databases or a network connection it no longer a unit test but already an integration test. A unit test framework might not be the right tool. – aggsol Jun 19 '13 at 08:18
  • You should mock your objects. Check http://stackoverflow.com/questions/2113697/unit-testing-asynchronous-function – Avram Tudor Jun 19 '13 at 08:19

3 Answers3

5

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.

Ian
  • 33,605
  • 26
  • 118
  • 198
  • Good idea, that works great for me! Thank you :) P.S. you got error in `while(asyncDone)` it should negate condition: `while(!asyncDone)` – Artem Zinnatullin Jun 19 '13 at 08:27
  • Why poll when there are plenty of better ways to wait for asynchronous code to complete. (`Manual/AutoResetEvent`, `Monitor`, etc.) or better yet if you are going to use something like the above, why not just `thread.Join()`? – Iridium Jun 19 '13 at 09:00
  • To expand on comment from @Iridium: or use async/await... (well actually Task.Wait()) – Paul Annetts Jun 19 '13 at 10:06
  • @Iridium: All good suggests, Updated my answer to reflect one of them. – Ian Jun 19 '13 at 10:40
2

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);
}
Paul Annetts
  • 9,554
  • 1
  • 27
  • 43
0

it's late but I guess this would be much more readable and authentic

await Task.Delay(TimeSpan.FromSeconds(5)); 
A.T.
  • 24,694
  • 8
  • 47
  • 65