How do I use Moq to mock an extension method?
Asked Answered
C

6

106

I am writing a test that depends on the results of an extension method but I don't want a future failure of that extension method to ever break this test. Mocking that result seemed the obvious choice but Moq doesn't seem to offer a way to override a static method (a requirement for an extension method). There is a similar idea with Moq.Protected and Moq.Stub, but they don't seem to offer anything for this scenario. Am I missing something or should I be going about this a different way?

Here is a trivial example that fails with the usual "Invalid expectation on a non-overridable member". This is a bad example of needing to mock an extension method, but it should do.

public class SomeType {
    int Id { get; set; }
}

var ListMock = new Mock<List<SomeType>>();
ListMock.Expect(l => l.FirstOrDefault(st => st.Id == 5))
        .Returns(new SomeType { Id = 5 });

As for any TypeMock junkies that might suggest I use Isolator instead: I appreciate the effort since it looks like TypeMock could do the job blindfolded and inebriated, but our budget isn't increasing any time soon.

Chromatography answered 18/2, 2009 at 17:48 Comment(4)
A duplicate can be found here: #2296460.Aarau
This question is an entire year older than that one. If there is duplication, it goes the other way.Chromatography
Still no appropriate solution in 2019!Tsarevitch
@Tsarevitch Actually, from many years you could use JustMock to mock extension methods. And is as simple as mocking any other method. Here is a link to the documentation : Extension Methods MockingChrisy
O
92

Extension methods are just static methods in disguise. Mocking frameworks like Moq or Rhinomocks can only create mock instances of objects, this means mocking static methods is not possible.

Overstrung answered 18/2, 2009 at 18:2 Comment(4)
@Mendelt..Then how would one unit test a method that internally has an extension method ? what are the possible alternatives ?Nylons
@Alexander I had the same question and then this answered it fantastically: agooddayforscience.blogspot.com/2017/08/… -Take a look at this, it is a life saver!Riedel
Above link is dead. Here is the archive web.archive.org/web/20190914122636/http://…Spracklen
The TL;DR of the blog post mentioned in the previous comment/s is as follows (taken directly from the post): "if you want to mock extension methods, don't try it, it won't work anyway. Instead mock the method belonging to the type that the extension method calls". The post was about mocking a specific static method; the methodology it describes will not be applicable to all situations; you will not be able to mock extension/static methods directly.Raman
C
42

If you can change the extension methods code then you can code it like this to be able to test:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

public static class MyExtensions
{
    public static IMyImplementation Implementation = new MyImplementation();

    public static string MyMethod(this object obj)
    {
        return Implementation.MyMethod(obj);
    }
}

public interface IMyImplementation
{
    string MyMethod(object obj);
}

public class MyImplementation : IMyImplementation
{
    public string MyMethod(object obj)
    {
        return "Hello World!";
    }
}

So the extention methods are only a wrapper around the implementation interface.

(You could use just the implementation class without extension methods which are sort of syntactic sugar.)

And you can mock the implementation interface and set it as implementation for the extensions class.

public class MyClassUsingExtensions
{
    public string ReturnStringForObject(object obj)
    {
        return obj.MyMethod();
    }
}

[TestClass]
public class MyTests
{
    [TestMethod]
    public void MyTest()
    {
        // Given:
        //-------
        var mockMyImplementation = new Mock<IMyImplementation>();

        MyExtensions.Implementation = mockMyImplementation.Object;

        var myClassUsingExtensions = new MyClassUsingExtensions();

        // When:
        //-------
        var myObject = new Object();
        myClassUsingExtensions.ReturnStringForObject(myObject);

        //Then:
        //-------
        // This would fail because you cannot test for the extension method
        //mockMyImplementation.Verify(m => m.MyMethod());

        // This is success because you test for the mocked implementation interface
        mockMyImplementation.Verify(m => m.MyMethod(myObject));
    }
}
Chronister answered 28/3, 2014 at 18:4 Comment(0)
C
17

I know this question hasn't been active for about a year but Microsoft released a framework to handle exactly this called Moles.

Here are a few tutorials as well:

  • DimeCasts.net
  • Nikolai Tillman's Tutorial
  • Centonze answered 28/4, 2010 at 20:35 Comment(0)
    E
    17

    I created a wrapper class for the extension methods that I needed to mock.

    public static class MyExtensions
    {
        public static string MyExtension<T>(this T obj)
        {
            return "Hello World!";
        }
    }
    
    public interface IExtensionMethodsWrapper
    {
        string MyExtension<T>(T myObj);
    }
    
    public class ExtensionMethodsWrapper : IExtensionMethodsWrapper
    {
        public string MyExtension<T>(T myObj)
        {
            return myObj.MyExtension();
        }
    }
    

    Then you can mock the wrapper methods in your tests and code with your IOC container.

    Earphone answered 1/10, 2010 at 14:30 Comment(4)
    This is a workaround where you cannot use the extension methods syntax anymore in your code. But it helps when you cannot change the extension methods class.Chronister
    @Chronister What do you mean by that? In your code you use MyExtension() from the MyExtensions class. In your tests, you use the MyExtension() from the ExtensionMethodsWrapper() class providing the parameter.Earphone
    If my class under test uses MyExtension() from the MyExtensions then I cannot mock the MyExtensions. So the class under test must use the IExtensionMethodsWrapper so it can be mocked. But then class under test cannot use extension method syntax anymore.Chronister
    That's the whole point of the OP. This is a workaround for that.Earphone
    P
    4

    For extension methods I normally use the following approach:

    public static class MyExtensions
    {
        public static Func<int,int, int> _doSumm = (x, y) => x + y;
    
        public static int Summ(this int x, int y)
        {
            return _doSumm(x, y);
        }
    }
    

    It allows to inject _doSumm fairly easy.

    Plassey answered 29/1, 2015 at 16:23 Comment(2)
    I just tried this but there's issues when passing the Parent mocked object that the extension is for when passing it into some other method which is in another assembly. In that case even with this technique the original extension is picked when the method is called in the other assembly, sort of a scoping issue. If I call directly in the Unit Test project it's fine though, but when you're testing other code which calls the extension method it just doesn't help.Standing
    @Stephen Not sure how to avoid this. I didn't ever had this kind of a scoping issuePlassey
    G
    2

    Best thing you can do is to provide a custom implementation for the type that has the extension method, e.g:

    [Fact]
    public class Tests
    {
        public void ShouldRunOk()
        {
            var service = new MyService(new FakeWebHostEnvironment());
    
            // Service.DoStuff() internally calls the SomeExtensionFunction() on IWebHostEnvironment
            // Here it works just fine as we provide a custom implementation of that interface
            service.DoStuff().Should().NotBeNull();
        }
    }
    
    public class FakeWebHostEnvironment : IWebHostEnvironment
    {
        /* IWebHostEnvironment implementation */
    
        public bool SomeExtensionFunction()
        {
            return false;
        }
    }
    
    Glomerulus answered 17/6, 2020 at 5:38 Comment(0)

    © 2022 - 2024 — McMap. All rights reserved.