当构造函数使用Func <t>

时间:2017-02-20 21:48:51

标签: c# moq func automocking

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 - 如果只需要做一个就很好,否则每个测试会有更多的开销。

2 个答案:

答案 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更好。

Documentation on Lazy