0

The original problem I have is that I am writing an integration test for which I want to spoof one small value returned from an IDbConnection instance. I don't want to have to spoof return values for every query. Instead I want all queries to actually hit the database and be processed normally, but for one SELECT I want to tweak the values. I envision it as a man-in-the-middle type of modification for a SELECT query.

I am using the Moq library and perhaps what I am trying to do is not possible. Here's a generic example of what I have tried for a made up interface (the 3rd attempt works but requires me to manually write a wrapper class that am hoping can be avoided):

using Moq;
using System;
namespace ConsoleApp1
{
    public interface IProcess
    {
        string Process1<T>(T t);
        string Process2<T, TA>(T t, TA ta);
    }

    public class Processor : IProcess
    {
        private Processor() { }
        public static Processor CreateProcessorFactoryMethod() { return new Processor(); }
        public string Process1<T>(T t) => "Processor.Process1";
        public string Process2<T, TA>(T t, TA ta) => "Processor.Process2";
    }

    public class Program
    {
        static void Main(string[] args)
        {
            IProcess existingProcessorInstance = Processor.CreateProcessorFactoryMethod();
            IProcess objectToTest = null;
            Mock<IProcess> mock = null;

            int attemptNumber = 3; //set this to the attempt you wish to try

            switch (attemptNumber)
            {
                case 1: //This doesn't work. First argument is actually a constructor parameter, but I want it to be the underlying instance to use.
                    mock = new Mock<IProcess>(existingProcessorInstance, MockBehavior.Loose); 
                    objectToTest = mock.Object;
                    break;
                case 2: //This also doesn't work. It thinks the first parameter is a parameter for the Processor constructor, but I want it to be the underlying instance to use.
                    var mockProcessor = new Mock<Processor>(existingProcessorInstance) { CallBase = true};
                    objectToTest = mockProcessor.Object;
                    break;
                case 3:
                    //this works, but I have to write a whole new Wrapper class for each interface I need to do this for, which is kind of a pain.
                    var wrapper = new WrapperForIProcess(existingProcessorInstance);
                    mock = wrapper.Mockery;
                    objectToTest = wrapper;
                    break;
                default:
                    throw new NotImplementedException();
            }

            //I want to mock this one specific call, but everything else should go through to the existingProcessorInstance.
            mock.Setup(m => m.Process1<string>(It.Is<string>(s => s == string.Empty)))
                .Returns((string t) => "Mock of Process1");

            Console.WriteLine(objectToTest.Process1<string>(string.Empty));    //expect: "Mock of Process1"
            Console.WriteLine(objectToTest.Process1<string>("asdf"));          //expect: "Processor.Process1"
            Console.WriteLine(objectToTest.Process2<int, double>(42, 1.0));    //expect: "Processor.Process2"   
        }


        /// <summary>
        /// Created for attempt #3
        /// </summary>
        public class WrapperForIProcess : IProcess
        {
            private readonly IProcess _processor;
            public WrapperForIProcess(IProcess processor)
            {
                _processor = processor;
                Mockery = new Mock<IProcess>(MockBehavior.Strict);
            }
            public Mock<IProcess> Mockery { get; }
            public string Process1<T>(T t) => WrapFunctionCall<string>(() => Mockery.Object.Process1(t), () => _processor.Process1(t));
            public string Process2<T, TA>(T t, TA ta) => WrapFunctionCall<string>(()=>Mockery.Object.Process2(t, ta), ()=>_processor.Process2(t,ta));

            private static T WrapFunctionCall<T>(Func<T> mockFunction, Func<T> wrappedObjectFunction)
            {
                try
                {
                    return mockFunction.Invoke();
                }
                catch(MockException)
                {
                    //assuming this is thrown due to no implementation provided in the mock (and strict behavior)
                    //so fall back to the behavior of the object we are wrapping.
                    return wrappedObjectFunction.Invoke();
                }
            }
        }
    }
}

Is there a better approach I should be taking? Is this even possible with Moq?

Anssssss
  • 3,087
  • 31
  • 40
  • You can mock `virtual` and `abstract` properties/methods with Moq. Any members which you don't mock will default to their concrete implementations (or stubs if they are abstract). So if the members you care about are virtual, then just add a `Setup` to those members, and you can (optionally) do a `Verify` for the assertion if you need it. – Kenneth K. Oct 24 '19 at 20:36
  • @KennethK. For that I assume you are saying to create the Mock like so "Mock", but that doesn't allow me to pass in an *existing* instance. If an instance can only be created by a factory method, then I can't setup a mock around that instance. – Anssssss Oct 24 '19 at 20:41
  • I think @KennethK. is referring to something like https://stackoverflow.com/questions/4769928/using-moq-to-mock-only-some-methods – KMoussa Oct 24 '19 at 22:21
  • If that is the case, it won't be suitable for my situation where I have an instance of an interface created by a factory method and I want to wrap *that particular instance* rather than create a new instance through some Mock constructor. – Anssssss Oct 25 '19 at 13:48

0 Answers0