Using Extension Methods to clean up Mocks (MoQ)

Mock’s can quickly become an ugly beast. They require lots of complex setup and verification. I have had good luck with using extension methods to simplify the complexity.

Assume we have the following code to implement our data layer on top of some ReST API.

public interface IWebClient
{
    string DownloadString(string url);
    string UploadValues(string method, string address, NameValueCollection data);
}
public class WebClientWrapper : IWebClient
{
    private WebClient client;

    public WebClientWrapper()
    {
        client = new WebClient();
    }

    public string DownloadString(string url)
    {
        return client.DownloadString(url);
    }

    public string UploadValues(string method, string address, NameValueCollection data)
    {
        return Encoding.UTF8.GetString(client.UploadValues(address, method, data));
    }
}

In the business/domain layer, we have a class that uses IWebClient to get some information from the API.

public class BusinessObject
{
    IWebClient client;

    public BusinessObject(IWebClient _client)
    {
        client = _client;
    }
    public XmlDocument FindCustomer(string search)
    {
        var result = client.DownloadString(
            string.Format("http://someApi/customers?search={0}",
                HttpUtility.UrlEncode(search))
            );

        return BuildXml(result);
    }
    public XmlDocument FindCustomer(char startsWith)
    {
        var result = client.DownloadString(
            string.Format("http://someApi/customers?startsWith={0}",
                HttpUtility.UrlEncode(startsWith.ToString()))
            );

        return BuildXml(result);
    }
    private XmlDocument BuildXml(string result)
    {
        var doc = new XmlDocument();
        doc.LoadXml(result);
        return doc;
    }
}

How do we go about testing this? My first attempt would look something like the following, relying heavily on MoQ.

[TestFixture]
public class BusinessObjectTests
{
    string resultXml = "<xml><customer></customer></xml>";
    Mock<iwebclient> client;
    BusinessObject bo;

    [SetUp]
    public void Setup()
    {
        client = new Mock<iwebclient>(MockBehavior.Strict);
        bo = new BusinessObject(client.Object);
    }

    [Test]
    public void Find_customer_using_search()
    {
        client.Setup(s => s.DownloadString("http://someApi/customers?search=searchVal"))
            .Returns(resultXml)
            .AtMostOnce();

        bo.FindCustomer("searchVal");

        client.VerifyAll();
    }

    [Test]
    public void Find_customer_using_filter()
    {
        client.Setup(s => s.DownloadString("http://someApi/customers?startsWith=a"))
            .Returns(resultXml)
            .AtMostOnce();

        bo.FindCustomer('a');

        client.VerifyAll();
    }
}

But I don’t like this. It is very verbose, and doesn’t resuse functionality very well. Morever, in real world examples, there would probably be many more functions with very similar setup and verification steps. How can we refactor this to make it better?

public static class ClientMockExtensions
{
    public static void VerifyGetContainedParmeter(this Mock<iwebclient> client, string name, string value)
    {
        client.Verify(c => c.DownloadString(
          It.Is<string>(s => s.IndexOf(name + "=" + value) > s.IndexOf("?"))));
    }
}
[TestFixture]
public class BusinessObjectTests
{
    string resultXml = "<xml><customer></customer></xml>";
    Mock<iwebclient> client;
    BusinessObject bo;

    [SetUp]
    public void Setup()
    {
        client = new Mock<iwebclient>(MockBehavior.Strict);
        bo = new BusinessObject(client.Object);

        client.Setup(s => s.DownloadString(
            It.Is<string>(str => str.StartsWith("http://someApi/customers"))))
            .Returns(resultXml)
            .AtMostOnce();
    }

    [Test]
    public void Find_customer_using_search()
    {
        bo.FindCustomer("searchVal");

        client.VerifyGetContainedParmeter("search", "searchVal");
        client.VerifyAll();
    }

    [Test]
    public void Find_customer_using_filter()
    {
        bo.FindCustomer('a');

        client.VerifyGetContainedParmeter("startsWith", "a");
        client.VerifyAll();
    }

In the example, I use extension methods to reuse verification steps, which also makes the tests much cleaner. Too many times developers stay away from complex verification steps in favor of complex setups. I think it is cleaner to do a more generic setup, and then use verify to get down to the specifics of what was done.