An Almost Foolproof Way to Mock Extension Method With Moq


Extension methods are a powerful feature of some programming languages. They allow you to create a new method without changing the existing class. But how to write the unit test for the extension method? Can you use Moq, a popular mocking library?

In recent years, more and more developers have been using the Moq framework to unit test their code.

There is a common misconception that you can use Moq to test extension methods directly. Unfortunately, this is not the case – to unit test extension methods using Moq, you first need to change the existing code.

This article will show you a code example of how to mock the extension method using Moq and explain the best approach to mock extension methods.

How to mock the extension method using Moq? – The problem

Unit testing is a process to test the functionality of small pieces, like classes or several classes that implement the desired behavior. They are also a helpful way to prevent bugs caused by extension methods.

In C#, extension methods are static methods that provide helpful syntax to make code that uses them more readable.

Implementing an extension method is useful but may affect the testability of the code. Extension methods allow you to add functionality to existing types without recompiling or creating derived types. This is because extension methods are used as if they are normal methods of the extended class.

Let’s see the code we want to test.

public class NetworkService
{
    private readonly ITestServer _server;

    public NetworkService(ITestServer server)
    {
        _server = server;
    }

    public IEnumerable<string> GetOrders()
    {
        HttpClient httpClient = _server.CreateClientWithRequestId();

        //other code
    }
}

So what’s the natural conclusion when you need to mock an extension method in tests? Use test doubles, stubs and mocks, right?

Using test doubles is a popular technique used in unit testing to control the behavior of dependency objects. A mock object checks if the system is interacting with the other objects properly. It can also check if a dependency was called with specific arguments.

Mocking is helpful in some cases because it helps you isolate the code you are testing. And one way to create test doubles on the fly is to use Moq, a mocking framework.

But what’s the problem with using mocks?

Let’s try to mock the extension method in the test.

[Fact]
public void GetOrders_returns_list_of_orders()
{
    var serverStub = new Mock<ITestServer>();

    serverStub.Setup(x => x.CreateClientWithRequestId());

    var networkService = new NetworkService(serverStub.Object);

    //other test code
}

When you run the test, you get the following error.

System.NotSupportedException : Unsupported expression: x => x.CreateClientWithRequestId()
Extension methods (here: TestServerExtensions.CreateClientWithRequestId) may not be used in setup / verification expressions.

Unfortunately, running the test case is unsuccessful and generates a system argument exception. The problem arises while trying to run the test because you can not mock an extension method.

Moq is a great tool for unit testing, but it has limitations. One limitation is that you cannot use Moq to test the extension method directly.

The extension method is not part of the class but is added to the class at runtime. This means that the extension method is not included when you try to use Moq to create a mock of the class. That’s why the above code fails to compile.

Instead, you must first change the existing code to write unit tests.

How to change the code to make it testable – The solution

One workaround is to create a wrapper class that contains the extension method. You can then use this wrapper class in the unit test.

To create a wrapper class, follow the steps in the article about unit testing the static method.

But there is another way.

Use Extract and Override Call refactoring.

Extract and override call is a refactoring technique that involves extracting the code that makes a call to a method on another object, and replacing it with a call to a method on a derived class. This allows the derived class to override the behavior of the base class.

It is a simple and powerful process used to deal with replacing the dependency directly.

The idea is to create a new protected method to wrap the call to the extension method. Then you subclass the original class for testing purposes and override the behavior of the protected method in the subclass.

Essentially, the dependency call inside the class gets extracted. In this case, the dependency is the call to the extension method.

Changing dependencies deep inside the call stack would be more complicated and time-consuming. This will override the virtual method you introduce so that it always returns what you want.

Use the following steps to perform Extract and Override Call:

  1. Use Extract Method refactoring to move the extension method call to a separate, new method.
  2. Make the method protected and virtual.
  3. Create a subclass of the original class in your testing project.
  4. Override the behavior in the new method.

Using the steps above, start by extracting the call to the extension method into a new protected method. The method should be protected and virtual.

public class NetworkService
{
    protected readonly ITestServer _server;

    public NetworkService(ITestServer server)
    {
        _server = server;
    }

    public IEnumerable<string> GetOrders()
    {
        HttpClient httpClient = CreateClient();

        //other code
        return null;
    }

    protected virtual HttpClient CreateClient()
    {
        return _server.CreateClientWithRequestId();
    }
}

Then, create a subclass in the test project and override the behavior. Make sure to set the _server field to protected in the NetworkService class.

class TestNetworkService : NetworkService
{
    public string RequestId { get; set; } =
            "761c40a8-1fd6-48bb-8efd-75f2b8d32530";

    public TestNetworkService(ITestServer server) : base(server)
    {
    }

    protected override HttpClient CreateClient()
    {
        //modify what kind of HttpClient you want to return
        var client = _server.CreateClient();

        client.DefaultRequestHeaders.Add("request", RequestId);

        return client;
    }
}

Finally, use the new class in the unit test itself.

[Fact]
public void GetOrders_returns_list_of_orders()
{
    var serverStub = new Mock<ITestServer>();
    var networkService = new TestNetworkService(serverStub.Object);

    //other test code
}

This approach makes your code cleaner and faster. In addition, using this technique saves time when you have large classes that are difficult to test.

While Moq is useful in unit testing, it cannot mock non-virtual methods and sealed classes.

Conclusion

Extension methods are useful but may impact the testability of your code. To make the code testable, you need to extract a virtual method with the call to the extension method and create a subclass in your test project. This is a part of the Extract and Override Call refactoring technique. With this approach, the dependency call is extracted, and the virtual method is overridden.

This simple solution improves the testability of your code.

Recent Posts