How to setup more complicated (IoC like) registration in AutoFixture

萝らか妹 提交于 2019-12-04 04:29:03

问题


Is it possible to reuse production IoC container registration in integration tests when using AutoFixture?

The problem is that I need the following fixture setup to inject mocks if dependency is not registered and inject "real" database related dependencies

var fixture = new Fixture().WithMocks().WithRealDatabase()

The solution I've tried

internal static Fixture WithMocks(this Fixture fixture)
{
    fixture.Customize(new AutoMoqCustomization());
}

internal static Fixture WithRealDatabase(this Fixture fixture)
{
    var containerBuilder = new Autofac.ContainerBuilder();
    ...
    containerBuilder.Register(c => c.Resolve<ISessionFactory>().OpenSession())
    containerBuilder.RegisterGeneric(typeof(Repository<>)).AsImplementedInterfaces()        
    containerBuilder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
        .Where(t => t.Name.EndsWith("Repository"))
        .AsImplementedInterfaces();
    ...
    fixture.Customizations.Add(new ContainerSpecimenBuilder(containerBuilder.Build()));
}

internal class ContainerSpecimenBuilder : ISpecimenBuilder
{
    private readonly IContainer container;

    public ContainerSpecimenBuilder(IContainer container)
    {
        this.container = container;
    }

    public object Create(object request, ISpecimenContext context)
    {
        var seededRequest = request as SeededRequest;

        if (seededRequest == null)
        {
            return new NoSpecimen(request);
        }

        var result = this.container.ResolveOptional(seededRequest.Request as Type);
        return result ?? new NoSpecimen(request);
    }
}

But the problem with this approach is that container.Resolve will not take into account already registered dependencies in AutoFixture.

Is there any alternative to solve this problem to have more complicated registrations?


回答1:


The general approach looks sound, but you should add the ContainerSpecimenBuilder to ResidueCollectors instead of to Customizations:

fixture.ResidueCollectors.Add(new ContainerSpecimenBuilder(containerBuilder.Build()));

AutoMoqCustomization also adds a node to ResidueCollectors, so you may need to experiment a bit with the specific ordering to figure out exactly how to make it behave like you want it to behave. The ordering matters.

For more information about the difference between Customizations and ResidueCollectors, see the AutoFixture architecture documentation.


A slightly simpler (and safer?) implementation of ContainerSpecimenBuilder could be just handling requests for Type instances directly, instead of for SeededRequest, as almost all SeededRequest values are relayed to requests for Type objects anyway:

internal class ContainerSpecimenBuilder : ISpecimenBuilder
{
    private readonly IContainer container;

    public ContainerSpecimenBuilder(IContainer container)
    {
        this.container = container;
    }

    public object Create(object request, ISpecimenContext context)
    {
        var t = request as Type;

        if (t == null)
            return new NoSpecimen(request);

        var result = this.container.ResolveOptional(t);
        return result ?? new NoSpecimen(request);
    }
}


来源:https://stackoverflow.com/questions/31740092/how-to-setup-more-complicated-ioc-like-registration-in-autofixture

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!