public class MyService
{
private readonly ISomething _something;
private readonly Func<IRarelyGetUsed> _rarelyGetUsed;
public MyService(ISomething something, Func<IRarelyGetUsed> rarelyGetUsed)
{
_something = something;
_rarelyGetUsed = rarelyGetUsed;
}
}
我们将AUTOFAC用于我们的IOC,发现我们可以使用Func<T>
方法获得很大的性能提升(在负载时),因为这些依赖性在使用之前才能解决,并且在某些情况下,某些依赖关系不使用。
我们还使用欧格进行某些单位测试。
var _container = new AutoMocker();
var _service = _container.CreateInstance<MyService>();
此时它炸开-System.NullReferenceException : Object reference not set to an instance of an object.
有人知道如何告诉欧克与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
-如果只需要进行一次,否则每个测试都有更多的开销。
您可以使用AutoMocker自动将Func<T>
连接到CC_9。
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>
的上述工作,您必须使用Func<T>
实例化Lazy<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()) });
}
}
您是否尝试过使用Lazy<T>
而不是Func<T>
来实现所需的懒惰加载?量可能比func发挥性能更好。
懒惰的文档