public class MyService
{
private readonly ISomething _something;
private readonly Func<IRarelyGetUsed> _rarelyGetUsed;
public MyService(ISomething something, Func<IRarelyGetUsed> rarelyGetUsed)
{
_something = something;
_rarelyGetUsed = rarelyGetUsed;
}
}
我们为我们的IOC使用Autofac,并发现使用Func<T>
方法可以获得很大的性能提升(在负载下),因为这些依赖关系在使用之前无法得到解决,并且在某些情况下确定不使用依赖项。
我们也在使用Moq进行一些单元测试。
var _container = new AutoMocker();
var _service = _container.CreateInstance<MyService>();
此时它会爆炸 - System.NullReferenceException : Object reference not set to an instance of an object.
任何人都知道如何告诉Moq很好地使用Func依赖项?
请注意,如果我将Func<IRarelyGetUsed>
更改为IRarelyGetUsed
,则没有例外。
编辑:原来nuget包已经过时了 - 更新软件包https://github.com/tkellogg/Moq.AutoMocker
后,现在正在运行。
然而,还有一个问题需要解决 -
_container.GetMock<Func<IRarelyGetUsed>>().Setup(p => p().DoSomething(It.IsAny<string>())).Returns(true).Verifiable();
尝试将上述方法的结果设置为 - Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.InvocationExpression'
编辑2:
var serviceMock = _container.GetMock<IRarelyGetUsed>();
serviceMock.Setup(r => r.DoSomething()).Returns(someData);
_container.GetMock<Func<IRarelyGetUsed>>().Setup(s => s()).Returns(serviceMock.Object);
以上现在可行,但是它需要同时设置Func<IRarelyGetUsed>
和IRarelyGetUsed
- 如果只需要做一个就很好,否则每个测试会有更多的开销。
答案 0 :(得分:2)
您可以使用AutoMocker自动为Func<T>
T
发送public void RegisterFuncs(AutoMocker autoMocker, IEnumerable<Type> types)
{
var use = typeof(AutoMocker).GetMethods()
.First(t => t.Name == "Use" &&
t.GetGenericArguments().First().Name == "TService");
var get = typeof(AutoMocker).GetMethod("Get");
foreach (var type in types)
{
// _.container.Use<Func<T>>()
var typedUse = use.MakeGenericMethod(typeof(Func<>).MakeGenericType(type));
// _container.Get<T>()
var typedGet = get.MakeGenericMethod(type);
var target = Expression.Constant(autoMocker);
var call = Expression.Call(target, typedGet);
// () => _container.Get<T>()
var lambda = Expression.Lambda(call);
// _.container.Use<Func<T>>(() => _container.Get<T>())
typedUse.Invoke(autoMocker, new object[] { lambda.Compile() });
}
}
// Then call with your AutoMocker instance and the interfaces you want to wire up
var types = typeof(SomeNamespace.ISomeInterface).Assembly.GetExportedTypes()
.Where(t => t.IsInterface && !t.ContainsGenericParameters);
RegisterFuncs(yourAutoMocker, types);
这样的内容:
Lazy<T>
在创建容器后立即在测试设置中运行。
注意:要为Lazy<T>
进行上述工作,您必须使用Func<T>
实例化public void RegisterLazys(AutoMocker autoMocker, IEnumerable<Type> types)
{
var use = typeof(AutoMocker).GetMethods()
.First(t => t.Name == "Use" &&
t.GetGenericArguments().First().Name == "TService");
var get = typeof(AutoMocker).GetMethod("Get");
foreach (var type in types)
{
// Lazy<T>
var lazyT = typeof(Lazy<>).MakeGenericType(type);
// _.container.Use<Lazy<T>>()
var typedUse = use.MakeGenericMethod(lazyT);
// _container.Get<T>()
var typedGet = get.MakeGenericMethod(type);
var target = Expression.Constant(autoMocker);
var call = Expression.Call(target, typedGet);
// () => _container.Get<T>()
var lambda = Expression.Lambda(call);
// _.container.Use<Lazy<T>>(new Lazy<T>(() => _container.Get<T>()));
typedUse.Invoke(autoMocker, new object[] { Activator.CreateInstance(lazyT, lambda.Compile()) });
}
}
,因此您需要以下内容:
picker
答案 1 :(得分:0)
您是否尝试过使用Lazy<T>
代替Func<T>
来实现您想要的延迟加载? Moq可能比Func更好。