Moq 创建实例失败,当构造函数具有使用 Func <T>的依赖项时


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发挥性能更好。

懒惰的文档

最新更新