Mocking Extension Methods

Mocking

Mocking is a technique where a dependency to a class is swapped out (mocked) with an alternate/fake equivalent to the functionality so that the class can be tested in isolation from it’s dependencies. For these examples, I’ll be using the mocking framework Moq.

Suppose we have a method that we wanted to mock:

1
2
3
4
5
6
7
8
9
10
11
public interface IPunctuation
{
string AddExclamationPoint(string s);
}

public class Punctuation : IPunctuation
{
public string AddExclamationPoint(string s) {
return s + "!";
}
}

We use the method like this:

1
2
3
var punctuation = new Punctuation();
var s = punctuation.AddExclamationPoint("Hello");
// Result: "Hello!"

Mocking this is fairly straighforward using Moq:

1
2
3
4
5
var punctuationMock = new Mock<IPunctuation>();
punctuationMock
.Setup(p => p.AddExclamationPoint(It.IsAny<string>()))
.Returns("HardcodedResult");
var punctuation = punctuationMock.Object;

Once mocked, we use it in the exact same way as we use the real Punctuation class, but with the mocked result:

1
2
var s = punctuation.AddExclamationPoint("Hello");
// Result: "HardcodedResult"

That’s mocking. For more on mocking, see Moq’s documentation.

Extension Methods

Extension methods in C# are static methods that provide some helpful syntax to make code that consumes them a little more readable (and chainable).

We can change the method above to an extension method by making the class and method static and by adding the this keyword:

1
2
3
4
5
6
public static class PunctuationExtensions
{
public static string AddExclamationPoint(this string s) {
return s + "!";
}
}

And the usage of the extension method is a little cleaner:

1
2
var s = "Hello".AddExclamationPoint();
// Result: "Hello!";

Mocking Extension Methods

I love to mock things when testing, and I love using extension methods, because I find both to be very helpful in writing clean, maintainable code. But how can we mock an extension method?

In the example above, how would I mock out the AddExclamationPoint() method from the PunctuationExtensions class?

Well, you can’t.

But you can get close. You can create a non-static method on a class that implements an interface, mock the method on the interface, and then create a extension method that acts as a wrapper around either the original method or the mocked method.

Goals:

  • Allow a class to call an extension method where we can mock out the implementation of what happens in that extension method
  • Do this without having too much extra boilerplate code
  • Avoid using complex solutions like Pex/Moles/IL weaving

We’re not going to really mock an extension method, but with a little extra code, we can get close enough for practical purposes.

To do this, we’ll need to keep the original Punctuation class and interface, as seen above:

1
2
3
4
5
6
7
8
9
10
11
public interface IPunctuation
{
string AddExclamationPoint(string s);
}

public class Punctuation : IPunctuation
{
public string AddExclamationPoint(string s) {
return s + "!";
}
}

Then we create a PunctuationExtensions class as a thin wrapper around the Punctuation class/interface, allowing an IPunctuation to be injected into the static extensions class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class PunctuationExtensions
{
private static IPunctuation defaultImplementation = new Punctuation();
public static IPunctuation Implementation { private get; set;}
= defaultImplementation;
public static void RevertToDefaultImplementation()
{

Implementation = defaultImplementation;
}

public static string AddExclamationPoint(this string s)
{

return Implementation.AddExclamationPoint(s);
}
}

We can then use it as an extension method without changing the class that
consumes it:

1
2
var s = "Hello".AddExclamationPoint();
// Result: "Hello!";

And we can also mock it when needed, using Moq:

1
2
3
4
5
6
7
8
9
10
var punctuationMock = new Mock<IPunctuation>();
punctuationMock.Setup(p => p.AddExclamationPoint(It.IsAny<string>()))
.Returns("HardcodedResult");

// Inject the mock so that it is used by the extension methods
PunctuationExtensions.Implementation = punctuationMock.Object;

// The next time we use the extension method, our mock will be used
var s = "Hello".AddExclamationPoint();
// Result: "HardcodedResult"

The key to this is line 6 where we set the Implementation property on the PunctuationExtensions class. This is where we make the extension method use the mocked implementation of IPunctuation so that we can run a test of our code without depending on the Punctuation class.

Cleanup

Don’t forget to clean up after your test by removing the mock. If you don’t do this, your mock will
stick around in the PunctuationExtensions class because it’s static.

1
PunctuationExtensions.RevertToDefaultImplementation();