3

给定以下使用 SimpleInjector 的开放通用 deocrator 链:

container.RegisterManyForOpenGeneric(typeof(IHandleQuery<,>), assemblies);
container.RegisterDecorator(
    typeof(IHandleQuery<,>),
    typeof(ValidateQueryDecorator<,>)
);
container.RegisterSingleDecorator(
    typeof(IHandleQuery<,>),
    typeof(QueryLifetimeScopeDecorator<,>)
);
container.RegisterSingleDecorator(
    typeof(IHandleQuery<,>),
    typeof(QueryNotNullDecorator<,>)
);

使用 SimpleInjector 2.4.0,我能够使用以下代码对其进行单元测试以断言装饰链:

[Fact]
public void RegistersIHandleQuery_UsingOpenGenerics_WithDecorationChain()
{
    var instance = Container
        .GetInstance<IHandleQuery<FakeQueryWithoutValidator, string>>();
    InstanceProducer registration = Container.GetRegistration(
        typeof(IHandleQuery<FakeQueryWithoutValidator, string>));

    instance.ShouldNotBeNull();
    registration.Registration.ImplementationType
        .ShouldEqual(typeof(HandleFakeQueryWithoutValidator));
    registration.Registration.Lifestyle.ShouldEqual(Lifestyle.Transient);
    var decoratorChain = registration.GetRelationships()
        .Select(x => new
        {
            x.ImplementationType,
            x.Lifestyle,
        })
        .Reverse().Distinct().ToArray();
    decoratorChain.Length.ShouldEqual(3);
    decoratorChain[0].ImplementationType.ShouldEqual(
        typeof(QueryNotNullDecorator<FakeQueryWithoutValidator, string>));
    decoratorChain[0].Lifestyle.ShouldEqual(Lifestyle.Singleton);
    decoratorChain[1].ImplementationType.ShouldEqual(
        typeof(QueryLifetimeScopeDecorator<FakeQueryWithoutValidator, string>));
    decoratorChain[1].Lifestyle.ShouldEqual(Lifestyle.Singleton);
    decoratorChain[2].ImplementationType.ShouldEqual(
        typeof(ValidateQueryDecorator<FakeQueryWithoutValidator, string>));
    decoratorChain[2].Lifestyle.ShouldEqual(Lifestyle.Transient);
}

更新到 SimpleInjector 2.6.1 后,此单元测试失败。现在似乎InstanceProducer.Registration.ImplementationType返回第一个装饰处理程序而不是装饰处理程序(意思是,它返回typeof(QueryNotNullDecorator<HandleFakeQueryWithoutValidator,string>)而不是typeof(HandleFakeQueryWithoutValidator).

此外,InstanceProducer.GetRelationships()不再返回链中的所有装饰器。它也只返回第一个装饰器。

这是一个错误吗?如果不是,我们如何使用 SimpleInjector 2.6.1+ 对开放的通用装饰器链进行单元测试?

4

2 回答 2

3

依赖图的可用细节在 2.6 中得到了极大的改进。您可以使用以下代码实现相同的目的:

[Fact]
public void RegistersIHandleQuery_UsingOpenGenerics_WithDecorationChain()
{
    var container = this.ContainerFactory();

    var instance = container
        .GetInstance<IHandleQuery<FakeQueryWithoutValidator, string>>();

    var registration = (
        from currentRegistration in container.GetCurrentRegistrations()
        where currentRegistration.ServiceType ==
            typeof(IHandleQuery<FakeQueryWithoutValidator, string>)
        select currentRegistration.Registration)
        .Single();
    Assert.Equal(
        typeof(QueryNotNullDecorator<FakeQueryWithoutValidator, string>), 
        registration.ImplementationType);
    Assert.Equal(Lifestyle.Singleton, registration.Lifestyle);

    registration = registration.GetRelationships().Single().Dependency.Registration;
    Assert.Equal(
        typeof(QueryLifetimeScopeDecorator<FakeQueryWithoutValidator, string>), 
        registration.ImplementationType);
    Assert.Equal(Lifestyle.Singleton, registration.Lifestyle);

    registration = registration.GetRelationships().Single().Dependency.Registration;
    Assert.Equal(
        typeof(ValidateQueryDecorator<FakeQueryWithoutValidator, string>), 
        registration.ImplementationType);
    Assert.Equal(Lifestyle.Transient, registration.Lifestyle);
}

你可以在这里找到更多信息

请注意:我认为你有一个俘虏依赖- 你在单例装饰器中有一个瞬态处理程序......

[Fact]
public void Container_Always_ContainsNoDiagnosticWarnings()
{
    var container = this.ContainerFactory();

    container.Verify();

    var results = Analyzer.Analyze(container);

    Assert.False(results.Any());
}
于 2014-12-27T16:49:35.393 回答
3

奎克是对的。我们极大地改进了注册和 KnownDependency 图的构建方式,特别是改进了诊断并让用户更容易查询注册。所以这不是错误;这是一个突破性的变化。然而,我们没想到有人会受到此影响,这就是我们在次要版本中进行更改的原因。很抱歉您不得不偶然发现此更改,但至少它只是测试代码中断。

在以前的版本中,添加装饰器时,KnownDependency 对象的图形会被展平。这使得查询和可视化对象图变得困难。在 v2.6 中,从诊断 API 的角度来看,装饰器就像是一个“真正的”注册。这意味着 InstanceProducer 和 Registration 对象现在显示返回的真实类型及其生活方式。

更清晰,但诊断 API 发生了重大变化。

于 2014-12-27T18:16:45.317 回答