gpt4 book ai didi

c# - 使用.NET Moq 时如何转发到另一个对象?

转载 作者:太空狗 更新时间:2023-10-30 01:16:27 28 4
gpt4 key购买 nike

给定一个对象,我想创建一个 mock,它实现对象的接口(interface)并模拟一个方法,但将其余方法转发给真实对象,而不是基类

例如:

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 ?

因此,在示例中我只想模拟 ISqlUtil.SpecialMethodToBeMocked 并将其余方法/属性转发给现有实例 sqlUtil

在 Moq.NET 中可以吗?

编辑 1

它也应该适用于泛型方法。

最佳答案

开箱即用的最小起订量无法做到这一点。但是,我认为如果您进入下一层并直接使用 CaSTLe DynamicProxy(这是 Moq 下的内容),您基本上可以实现您想要的。

因此,给定以下基本代码来模拟您的问题(本质上是一个接口(interface)、一个具体实现和一个工厂,因为具体很难制作/设置):

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,将方法调用委托(delegate)给创建代理时提供的具体对象。

示例代码使用字符串而不是 lambda 来指定拦截方法,显然这可以更改(读者练习)。此外,这没有使用 Moq,因此您丢失了 SetupReturnsVerify 元素,它们被拦截器取代,所以这可能与您所追求的目标相距太远而无用,但是根据您的代码的实际情况,它可能是一种可行的替代方法。

关于c# - 使用.NET Moq 时如何转发到另一个对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35142517/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com