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?