9

Given an object, I would like to create a mock that implements the interface of the object and mocks one method, but forwards the rest of the methods to the real object, not the base class.

For example:

ISqlUtil sqlUtil = GetTheRealSqlUtilObjectSomehow(...);
var mock = new Mock<ISqlUtil>();
mock.Setup(o => o.SpecialMethodToBeMocked(...)).Returns<...>(...)
// Here I would like to delegate the rest of the methods to the real sqlUtil object. How ?

So, in the example I want to mock just ISqlUtil.SpecialMethodToBeMocked and forward the rest of methods/properties to the existing instance sqlUtil.

Is it possible in Moq.NET ?

EDIT 1

It should work for generic methods as well.

mark
  • 59,016
  • 79
  • 296
  • 580
  • I just stumbled across your post while answering a similar [question](https://stackoverflow.com/questions/59660284/creating-mock-with-moq-around-existing-instance/59664654#59664654): I believe you can indeed trick Moq into doing what you initially wanted. – timur Jan 09 '20 at 13:13
  • @timur Please provide your answer. – mark Jan 09 '20 at 13:53

4 Answers4

9

You can't do this with Moq out of the box. However, I think you can achieve basically what you want if you go down to the next layer and use Castle DynamicProxy directly (which is what's underneath Moq).

So, given the following base code to simulate your issue (essentially, an interface, a concrete implementation and a factory because the concrete is hard to make/setup):

public interface ISqlUtil {
    T SomeGenericMethod<T>(T args);

    int SomeMethodToIntercept();
}
public class ConcreteSqlUtil : ISqlUtil {
    public T SomeGenericMethod<T>(T args){
        return args;
    }
    public int SomeMethodToIntercept() {
        return 42;
    }
}
public class SqlUtilFactory {
    public static ISqlUtil CreateSqlUtil() {
        var rVal = new ConcreteSqlUtil();
        // Some Complex setup
        return rVal;
    }
}

You can then have the following test:

public void TestCanInterceptMethods() {
    // Create a concrete instance, using the factory
    var coreInstance = SqlUtilFactory.CreateSqlUtil();

    // Test that the concrete instance works
    Assert.AreEqual(42, coreInstance.SomeMethodToIntercept());
    Assert.AreEqual(40, coreInstance.SomeGenericMethod(40));

    // Create a proxy generator (you'll probably want to put this
    // somewhere static so that it's caching works if you use it)
    var generator = new Castle.DynamicProxy.ProxyGenerator();

    // Use the proxy to generate a new class that implements ISqlUtil
    // Note the concrete instance is passed into the construction
    // As is an instance of MethodInterceptor (see below)
    var proxy = generator.CreateInterfaceProxyWithTarget<ISqlUtil>(coreInstance, 
                                new MethodInterceptor<int>("SomeMethodToIntercept", 33));

    // Check that calling via the proxy still delegates to existing 
    // generic method
    Assert.AreEqual(45, proxy.SomeGenericMethod(45));
    // Check that calling via the proxy returns the result we've specified
    // for our intercepted method
    Assert.AreEqual(33, proxy.SomeMethodToIntercept());
}

The method interceptor looks like this:

public class MethodInterceptor<T> : Castle.DynamicProxy.IInterceptor {
    private T _returns;
    private string _methodName;
    public MethodInterceptor(string methodName, T returns) {
        _returns = returns;
        _methodName = methodName;
    }
    public void Intercept(IInvocation invocation) {
        if (invocation.Method.Name == _methodName) {
            invocation.ReturnValue = _returns;
        }
        else {
            invocation.Proceed();
        }
    }
}

Essentially, the interceptor checks if the method being called matches the one you're interested in and if so, returns the stored return value. Otherwise, it calls Proceed, which delegates the method call onto the concrete object supplied when the proxy was created.

The example code uses strings rather than lambdas to specify the method to intercept, obviously this could be changed (exercise for the reader). Also, this isn't using Moq, so you lose the Setup, Returns and Verify elements, which are replaced by the Interceptor, so this may be too far away from what you're after to be useful, however depending what your code really looks like it may be a viable alternative approach.

forsvarir
  • 10,749
  • 6
  • 46
  • 77
2

If you're unable to mock the class and delegate calls to the base by default, then you'll have to manually wire up the delegation to your separate instance.

var util = GetSqlUtil();

var mockUtil = new Mock<ISqlUtil>(MockBehavior.Strict);
mockUtil.Setup(x => x.SomeCall(...)).Returns<...>(args => util.SomeCall(args));
Chris Hannon
  • 4,134
  • 1
  • 21
  • 26
  • 1
    That part I get. The essence of the question is that I do not want to do it. That sounds like something that could be part of the Moq functionality. – mark Feb 02 '16 at 00:16
  • Sure, and that's not something that it does as far as I know. I would argue, however, that if you require actual functionality from your mocks then you are widening the scope of the test a little too much and testing the wrong thing. You're testing method A, which takes an instance of interface B and performs several calls on it. You want to see how method A behaves __if B returns specific values__. You don't actually care about making B __do that__, you want to make sure A is written correctly for a certain case. Mock everything you need for the results you need, no more. – Chris Hannon Feb 02 '16 at 00:25
  • 2
    I am writing integration tests and this particular class talks to the database, I do not mock it, because I do want it to talk to the database, But I do want to have certain change in the functionality that is only needed in one method and only during the testing. – mark Feb 02 '16 at 00:31
0

Having been successful with tricking Moq into creating a proxy for given class instance in my other SO answer here, I thought it would be easy to tweak the solution for your case of a given interface implementation.

No way

If you think of, it it makes sense: interface has no implementateion. And since Moq is aware mocked type is an interface - it does not even try to call the underlying proxy. That's it, end of story.

For those who don't give up easily

spoiler: still no luck

Looking at the library source code, I had a theory that it might be possible to force the correct execution path:

if (mock.TargetType.IsInterface) // !!! needs to be true here
{
    // !!! we end up here and proceed to `DefaultValueProvider`
}
else
{
    Debug.Assert(mock.TargetType.IsClass); // !!! needs to pass here
    Debug.Assert(mock.ImplementsInterface(declaringType)); // !!! needs to pass here

    // Case 2: Explicitly implemented interface method of a class proxy.
......

for that we could fulfill two conditions:

  1. mock.TargetType should be a target class instance type
  2. this.InheritedInterfaces should contain our interface

the second one is easy enough to build:

private void AddInheritedInterfaces(T targetInstance)
{
    var moqAssembly = Assembly.Load(nameof(Moq));
    var mockType = moqAssembly.GetType("Moq.Mock`1");
    var concreteType = mockType.MakeGenericType(typeof(T));
    var fi = concreteType.GetField("inheritedInterfaces", BindingFlags.NonPublic | BindingFlags.Static);
    
    var t = targetInstance.GetType()
        .GetInterfaces()
        .ToArray();
    fi.SetValue(null, t);
}

but as far as I'm aware, overriding an expression-bodied property marked internal (which Mock<>.TargetType is) is impossible without Reflection.Emit artillery, where it will likely become infeasible due to amonunt of overriding and subclassing required - you might be better off just forking Moq and patching the source code in this case (or submitting a PR maybe?).

What can be done

It should be possible to generate Setup LINQ expressions that automatically call through to your respective instance implementations:

//something along these lines, but this is basically sudocode
ISqlUtil sqlUtil = GetTheRealSqlUtilObjectSomehow(...);
var mock = new Mock<ISqlUtil>();
foreach(var methodInfo in typeof(ISqlUtil).GetMembers()) 
{   mock.Setup(Expression.Member(methodInfo)).Returns(Expression.Lambda(Expression.Call(methodInfo)).Compile()())
}

But given how much effort it is to account for everything properly, that again is probably not very feasible.

Community
  • 1
  • 1
timur
  • 14,239
  • 2
  • 11
  • 32
0

There is a workaround to do it, by using the method by @timur described in this answer.

While this method doesn't work directly on interfaces as described by his answer in the current thread, but it is indeed possible to do it via a generic factory method.

NOTE: The resulting Moq object will NOT be a true subclass rather it is a wrapped object and therefore only public virtual methods will be forwarded to the object (unlike a typical Moq which the base is automatically called for non public or non virtual methods/properties).

The factory mode would look like this:

static MyMock<T> CreateMock<T>(T target) where T : class, ISqlUtil
{
     var superMock = new MyMock<T>(target); // now we can pass instances!

     superMock.CallBase = true; 
     superMock.Setup(o => o.SpecialMethodToBeMocked(...)).Returns<...>(...);
     return superMock;
}

And you use it like this:

var mockFunc = typeof(this).GetMethod("CreateMock").MakeGenericMethod(sqlUtil.GetType());
var superMock = mockFunc.Invoke(null, new object[] {sqlUtil}) as Mock;

While the implementation of MyMock will be based on the one described in this answer (but I am simplifying it a bit).

public class MyMock<T> : Mock<T>, IDisposable where T : class
{
     public MyMock(T targetInstance)
     {
          var moqAssembly = typeof(Mock).Assembly;

          var proxyFactoryType = moqAssembly.GetType("Moq.ProxyFactory");
          var castleProxyFactoryInstance = proxyFactoryType.GetProperty("Instance").GetValue(null);

          var castleProxyFactoryType = moqAssembly.GetType("Moq.CastleProxyFactory");
          var generatorFieldInfo = castleProxyFactoryType.GetField("generator", BindingFlags.NonPublic | BindingFlags.Instance);
         
          generatorFieldInfo.SetValue(castleProxyFactoryInstance, new MyProxyGenerator(targetInstance)); 
     }
}

class MyProxyGenerator : ProxyGenerator
{
   object _target;

   public MyProxyGenerator(object target) {
     _target = target;
}
// this method is 90% taken from the library source. I only had to tweak two lines (see below)
public override object CreateClassProxy(Type classToProxy, Type[] additionalInterfacesToProxy, ProxyGenerationOptions options, object[] constructorArguments, params IInterceptor[] interceptors)
{
    if (_target is not null) return CreateClassProxyWithTarget(classToProxy, additionalInterfacesToProxy, _target, options, constructorArguments, interceptors);
    return base.CreateClassProxy(classToProxy, additionalInterfacesToProxy,  options, constructorArguments, interceptors);
}
yoel halb
  • 12,188
  • 3
  • 57
  • 52