How to unit test open common decorator chains in SimpleInjector 2.6.1+

Given the following open common deocrator chain using SimpleInjector:

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

      

With SimpleInjector 2.4.0 I was able to unit test this to validate the trim chain using the following code:

[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);
}

      

After upgrading to SimpleInjector 2.6.1, this unit test fails. It seems to InstanceProducer.Registration.ImplementationType

now return the first decoration's handler, not the handled handler (which means it returns typeof(QueryNotNullDecorator<HandleFakeQueryWithoutValidator,string>)

instead of typeof(HandleFakeQueryWithoutValidator)

.

Also, InstanceProducer.GetRelationships()

no longer returns all decorators in the chain. it also only returns the first decorator.

Is this a bug, and if not, how can we unit test open common decorator chains with SimpleInjector 2.6.1+?

+3


source to share


2 answers


The details available for the dependency graph have improved significantly in 2.6. You can do the same with this code:

[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);
}

      

You can find more information here



Please note, I think you have a playoff dependency - you have a temporary handler inside a singleton decorator ...

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

    container.Verify();

    var results = Analyzer.Analyze(container);

    Assert.False(results.Any());
}

      

+3


source


Qujck is right. We've made significant improvements to the way registrations are registered and KnownDependency graphics, especially to improve diagnostics and make it easier for users to register. So this is not a mistake; this is an amazing change. We didn’t expect anyone to get hurt by this, however, and so we made changes to a minor release. I'm sorry you had to stumble upon this change, but at least it's just a test of the code that's breaking.

In previous versions, the graph of KnownDependency objects was flattened when decorators were added. This made querying and rendering the object graph tough. In 2.6, from the point of view of the diagnostic API, it is as if the decorator is a "real" registration. This means that the InstanceProducer and Registration objects now represent the real type that is being returned and its lifestyle.



Significantly clearer, but changes the diagnostic API.

+3


source







All Articles