Saturday, February 22, 2014

Unit Testing Async Methods with Moq

The other day I was pairing with a colleague.  We where working on unit testing some classes that where using the new async and await features.  We ran into some issue trying to get mocking working for our classes dependencies. Here is some example code on how we got things to work.

So given the following code:

public interface IClass2
{
    Task<string> GetSomeString_MethodAsync();
}

public class Class2 : IClass2
{
    public async Task<string> GetSomeString_MethodAsync()
    {
        await Task.Run(() => Thread.Sleep(2000));
        return "hello world.";
    }
}

public class Class1
{
    private IClass2 class2;

    public Class1(IClass2 class2)
    {
        this.class2 = class2;
    }

    public async Task<string> SomeMethod()
    {
        return await this.class2.GetSomeString_MethodAsync();
    }
}

And we can test it like this:

private Mock<IClass2> class2Mock;
private Class1 class1;

[TestInitialize]
public void Setup()
{
    this.class2Mock = new Mock<IClass2>();
    this.class1 = new Class1(this.class2Mock.Object);
}
            
[TestMethod]
public async Task SomeMethodTest()
{
    var expectedString = "Hello World";
    var tcs = new TaskCompletionSource<string>();
    tcs.SetResult(expectedString);
    this.class2Mock.Setup(x => x.GetSomeString_MethodAsync()).Returns(tcs.Task);

    var result = await this.class1.SomeMethod();

    Assert.AreEqual(result, expectedString);
}

Note the usage of the TaskCompletionSource in the unit test along with the declaration of the test using “async Task”.