Вы не можете сделать это с помощью Moq из коробки. Тем не менее, я думаю, вы можете достичь в основном того, что хотите, если перейдете к следующему слою и напрямую используйте Castle DynamicProxy (это то, что находится под Moq).
Таким образом, учитывая следующий базовый код для имитации вашего вопроса (по существу, интерфейса, конкретную реализации и завода, потому что бетон трудно сделать/Настройка):
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;
}
}
Вы можете иметь следующий тест:
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());
}
метод перехватчик выглядит следующим образом:
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();
}
}
}
По сути, перехватчик проверяет, соответствует ли тот метод, который вас интересует, и если да, возвращает возвращаемое значение. В противном случае он вызывает Proceed
, который делегирует вызов метода на конкретный объект, предоставленный при создании прокси.
В примере кода используются строки, а не лямбда, чтобы указать метод для перехвата, очевидно, это можно было бы изменить (упражнение для читателя). Кроме того, это не использование Moq, поэтому вы теряете элементы Setup
, Returns
и Verify
, которые заменяются Interceptor, поэтому это может быть слишком далеко от того, что вам нужно, чтобы быть полезным, однако в зависимости от вашего кода похоже, что это может быть жизнеспособным альтернативным подходом.
Это самое близкое к тому, что мне нужно, слишком плохо Moq не поддерживает его. – mark