Monday, 6 January 2014

Unit testing async marked methods using mock library

Have you ever tried unit testing a method marked with async? There’s a known problem of unit testing the Async marked methods. When Nunit tried to run the test with mocked Async methods it goes in Infinite wait. There are many discussion on the internet for the same giving you the solutions and work around. This post will provide you with another solution.

Let’s start and setup a test project to reproduce the problem. So first we need library that contains the methods marked with Async keyword.

First we need the marker interface:

IHttpDownloader.cs

public interface IHttpDownloader
{
    Task<string> DownloadContentAsync(Uri httpUri);
}

Implementation:


HttpDownloader.cs



public class HttpDownloader : IHttpDownloader
{
    public async Task<string> DownloadContentAsync(Uri httpUri)
    {
        RawHttpDownloader downloader = new RawHttpDownloader();
 
       return await downloader.DownloadAsync(httpUri);
    }
}

Helper class:


RawHttpDownloader.cs



public class RawHttpDownloader
{
    public async Task<string> DownloadAsync(Uri httpUri)
    {
        return string.Format("Dummy downloaded string from {0}", httpUri.AbsolutePath);
    }
}


Now lets write a unit test to test this method for a positive scenario. Here I have used the Nunit to write the tests:



[TestFixture]
public class HttpDownloaderTest
{
    [Test]
    public void DownloadContentAsync_ValidHttpAddress_ReturnsData()
    {
        var repository = new MockRepository();
        var httpUri = new Uri("http://www.google.com/about");
 
        var downloaderStub = repository.Stub<IHttpDownloader>();
 
        // setup
        var task = new Task<String>(
            () => { return "test string"; });
 
        downloaderStub.Expect(s => s.DownloadContentAsync(httpUri)).Return(task);
 
        // act
        repository.ReplayAll();
 
        var restult = downloaderStub.DownloadContentAsync(httpUri);
 
       Assert.IsNotNull(restult.Result);
 
        repository.VerifyAll();
    }
}

If you try to run this test It will go in Infinite state:


image


Problem caused by the Nunit framework as it doesn’t support the methods marked with Async keyword for tests. So it kept on waiting for the asynchronous method and it actually never invokes the Task returned into start state.


Solution:


Since the Nunit doesn’t actually invokes the underlying task to start state so you what you just have to do is Start the task manually.


image


 


Download the complete sample from here.