Faking extension methods

I just read a post from Daniel Cazzulino about mocking extension methods. He wants to mock an extension method so that it behaves as he defines in his test, instead of actually calling the real method.

To do this, Daniel creates an interface where every method signature is copied to, modifies the original static class so it’s not static anymore and holds a reference to the object that the extension method was for in the first place. It’s a really cool article, but as Daniel says himself “This is more work, I know, but now you can…”

I break him off there. You know what I have to write to mock my extension methods? Here’s the code:

//
//
//

How do I do this? Easy, I’m using Typemock Isolator. Imagine I’ve got the following extension method:

public static class MessagingExtensions
{
    public static SendResult SendTo(this SomeType target, string address)
    {
        // Do something
        throw new NotImplementedException("Don't do anything!!!");
    }
}

The extension method is for the type SomeType, which doesn’t have any members. It’s just here for show. I’ve explicitly added the exception so we’ll be sure this method will never get executed. I’ve also got a Worker class that I want to test.

public class Worker
{
    public SendResult Execute()
    {
        SomeType st = new SomeType();
        return st.SendTo("[email protected]");
    }
}

I want to test if everything goes well with this method. It doesn’t do anything exciting, so there aren’t a lot of options, but this method isn’t what this article is about. What we want to see is that the extension method SendTo is never actually called. So how about it? Here’s my test:

[TestMethod, Isolated]
public void ExecuteSucceeds()
{
    // Arrange
    Isolate.Fake.StaticMethods(typeof(MessagingExtensions));
    Isolate.WhenCalled(() => MessagingExtensions.SendTo(null, "")).WillReturn(SendResult.Sent);

    // Act
    Worker worker = new Worker();
    SendResult result = worker.Execute();

    // Assert
    Assert.AreEqual<SendResult>(SendResult.Sent, result);
    Isolate.Verify.WasCalledWithAnyArguments(() => MessagingExtensions.SendTo(null, ""));
}

Line 5 makes sure that all static methods to MessagingExtensions are never actually called, and for our demo this isn’t even necessary.

Line 6 makes sure that when SendTo is called, it will return the right result.

Line 13 is actually a bogus verification, because I’m really testing here if Isolator is returning the right result. But to be sure, we’ll keep it in. Line 14 verifies if the extension method was called, as we expected to.

So to conclude, I did not write one line of code extra to mock away the extension method. This is thanks to Typemock Isolator, the tool you just have to have when you’re doing unit testing.

Update february 23, 2009

Eli Lopian commented that you can also call the extenson method on the extended type directly, as shown in the code below.

// Arrange
var dummy = new SomeType();
Isolate.WhenCalled(() => dummy.SendTo("")).WillReturn(SendResult.Sent);

// Assert
Isolate.Verify.WasCalledWithAnyArguments(() => dummy.SendTo(""));

Update februari 23, 2009

You can find a VS2008 solution here, so you can see what’s actually happening.

You may also like...

3 Responses

  1. Eli Lopian says:

    Great post Dennis.
    Did you know that you don’t have to call the extension type, but can call the extension method directly on the extended type.

    // Arrange
    var dummy = new SomeType();
    Isolate.WhenCalled(() => dummy.SendTo(“”)).WillReturn(SendResult.Sent);

  2. Dennis van der Stelt says:

    Thanks Eli for the remark, added the info to the post.
    Also added a solution to download and see what’s actually happening.

  3. I have done this on several websites, however its much easier to do it in IIS…

    I make xml files act as ASP files so i can process code on the server-side and output xml.

Click on a tab to select how you'd like to leave your comment

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.