Mocking Extension Methods with Moq
Asked Answered
H

8

269

I have a pre-existing Interface...

public interface ISomeInterface
{
    void SomeMethod();
}

and I've extended this interface using a mixin...

public static class SomeInterfaceExtensions
{
    public static void AnotherMethod(this ISomeInterface someInterface)
    {
        // Implementation here
    }
}

I have a class thats calling this which I want to test...

public class Caller
{
    private readonly ISomeInterface someInterface;

    public Caller(ISomeInterface someInterface)
    {
        this.someInterface = someInterface;
    }

    public void Main()
    {
        someInterface.AnotherMethod();
    }
}

and a test where I'd like to mock the interface and verify the call to the extension method...

    [Test]
    public void Main_BasicCall_CallsAnotherMethod()
    {
        // Arrange
        var someInterfaceMock = new Mock<ISomeInterface>();
        someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable();

        var caller = new Caller(someInterfaceMock.Object);

        // Act
        caller.Main();

        // Assert
        someInterfaceMock.Verify();
    }

Running this test however generates an exception...

System.ArgumentException: Invalid setup on a non-member method:
x => x.AnotherMethod()

My question is: Is there a nice way to mock out the mixin call?

Hesione answered 19/2, 2010 at 11:41 Comment(3)
In my experience, the terms mixin and extension methods are separate things. I'd use the latter in this instance to avoid mixups :PCarmagnole
Duplicate of: #562629.Cybele
Does this answer your question? How do I use Moq to mock an extension method?Induct
N
62

I have used a Wrapper to get around this problem. Create a wrapper object and pass your mocked method.

See Mocking Static Methods for Unit Testing by Paul Irwin, it has nice examples.

Nickelous answered 25/11, 2014 at 19:59 Comment(2)
I like this answer because what it is saying (without directly saying it) is you need to alter your code to make it testable. That's just how it works. Understand that in microchip/IC/ASIC design, those chips have to not only be designed to work, but designed even further to be testable, because if you can't test a microchip, it is useless - you can't guarantee it will work. Same goes for software. If you haven't built it to be testable, it's ... useless. Build it to be testable, which in some cases means rewriting code (and using wrappers), and then build the automated tests that test it.Engird
I created a small library that wraps Dapper, Dapper.Contrib, and IDbConnection. github.com/codeapologist/DataAbstractions.DapperGelatinate
B
42

You can't "directly" mock static method (hence extension method) with mocking framework. You can try Moles (http://research.microsoft.com/en-us/projects/pex/downloads.aspx), a free tool from Microsoft that implements a different approach. Here is the description of the tool:

Moles is a lightweight framework for test stubs and detours in .NET that is based on delegates.

Moles may be used to detour any .NET method, including non-virtual/static methods in sealed types.

You can use Moles with any testing framework (it's independent about that).

Baldric answered 23/8, 2011 at 6:20 Comment(2)
Besides Moles, there are other (non-free) mocking frameworks that use .NET's profiler API to mock objects and so can replace any calls. The two I know are Telerik's JustMock and TypeMock Isolator.Semiannual
Moles in theory is good, but I found three issues when I trialed it that stopped me using it... 1) It doesn't run in the Resharper NUnit runner 2) You need to manually create a mole assembly for each stubbed assembly 3) You need to manually recreate a mole assembly whenever a stubbed method changes.Hesione
H
34

I found that I had to discover the inside of the extension method I was trying to mock the input for, and mock what was going on inside the extension.

I viewed using an extension as adding code directly to your method. This meant I needed to mock what happens inside the extension rather than the extension itself.

Hermes answered 7/3, 2017 at 17:32 Comment(2)
This is not always possible. E.g. when using a non-open source extension you didn't write.Golconda
This answer helped me moq.Verify() a derivative of Microsoft.Extensions.Logging.ILogger . Thank you!Diabetes
E
7

If you just want to make sure that the extension method was invoked, and you aren't trying to setup a return value, then you can check the Invocations property on the mocked object.

Like this:

var invocationsCount = mockedObject.Invocations.Count;
invocationsCount.Should().BeGreaterThan(0);
Eddo answered 24/6, 2021 at 20:52 Comment(2)
For a return value we used the Callback feature of MoqRiggall
Just what I was trying to do.Caius
C
6

I like to use the wrapper (adapter pattern) when I am wrapping the object itself. I'm not sure I'd use that for wrapping an extension method, which is not part of the object.

I use an internal Lazy Injectable Property of either type Action, Func, Predicate, or delegate and allow for injecting (swapping out) the method during a unit test.

    internal Func<IMyObject, string, object> DoWorkMethod
    {
        [ExcludeFromCodeCoverage]
        get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); }
        set { _DoWorkMethod = value; }
    } private Func<IMyObject, string, object> _DoWorkMethod;

Then you call the Func instead of the actual method.

    public object SomeFunction()
    {
        var val = "doesn't matter for this example";
        return DoWorkMethod.Invoke(MyObjectProperty, val);
    }

For a more complete example, check out http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/

Capua answered 12/8, 2016 at 15:53 Comment(3)
This is good, but readers should be aware that _DoWorkMethod is a new field of the class which each instance of the class now has to allocate one more field. It's rare that this matters, but sometimes it does depending on the number of instances you're allocating at any one time. You can work around this problem by making _DoWorkMethod static. The downside to that is that if you have unit tests running concurrently, two different unit tests that may modify the same static value will complete.Bielefeld
Very lean and tidyRiggall
I use both delegate and protected method in different situations, a protected method is a good solution because of cleaner code to return a mocked result but it's not a good option to ".Verify" , on the other hand we can ".Verify" the Mock<Func<...>>. Though so far my best soltion was to make the delegate prop private and have an internal prop "internal string MockableMethodPropName => nameof(MockableMethod);" so I set it using Reflection in the unit test setup.Bobsleigh
S
4

Reason why it is not possible to mock an extension method is already given in good answers. I am just trying to give another possible solution with this answer: Extract a protected, virtual method with the call to the extension method and create a setup for this method in the test class/method by using a proxy.

public class Foo
{
  public void Method()
    => CallToStaticMethod();

  protected virtual void CallToStaticMethod()
    => StaticClass.StaticMethod();
}

and test

[TestMethod]
    public void MyTestMethod()
    {
        var expected = new Exception("container exception");
        var proxy = new Mock<Foo>();
        proxy.Protected().Setup("CallToStaticMethod").Throws(expected);

        var actual = Assert.ThrowsException<Exception>(() => proxy.Object.Foo());

        Assert.AreEqual(expected, actual);
    }
  
Stallings answered 13/10, 2021 at 13:4 Comment(0)
F
1

In my case extension method is a method around some public method of my class. So I checked call of that internal method. That approach is similar to Alvis answer (above).

Flagellum answered 14/9, 2022 at 5:38 Comment(0)
S
-4

So if you are using Moq, and want to mock the result of an Extension method, then you can use SetupReturnsDefault<ReturnTypeOfExtensionMethod>(new ConcreteInstanceToReturn()) on the instance of the mock class that has the extension method you are trying to mock.

It is not perfect, but for unit testing purposes it works well.

Sardine answered 31/1, 2020 at 16:7 Comment(3)
I believe it's SetReturnsDefault<T>()Expedient
that does never return the concrete instance. Just null in case of a custom c# class!Recipience
An example would be nice. I can not make it work.Riemann

© 2022 - 2024 — McMap. All rights reserved.