如何在AutoFixture中设置更复杂(IoC类似)的注册

使用AutoFixture时,是否可以在集成测试中重用生产IoC容器注册?

问题是,如果未注册依赖项,我需要以下fixture设置来注入模拟并注入“真正的”数据库相关依赖项

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

我试过的解决方案

 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().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); } } 

但是这种方法的问题是container.Resolve不会考虑AutoFixture中已注册的依赖项。

是否有任何替代方案可以解决此问题,以便进行更复杂的注册?

一般方法看起来很合理,但您应该将ContainerSpecimenBuilder添加到ResidueCollectors而不是Customizations

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

AutoMoqCustomization还向ResidueCollectors添加了一个节点,因此您可能需要对特定排序进行一些实验,以确切了解如何使其表现得像您希望它的行为。 订购很重要 。

有关CustomizationsResidueCollectors之间区别的更多信息,请参阅AutoFixture体系结构文档 。


ContainerSpecimenBuilder一个稍微简单(且更安全?)的实现可能只是直接处理Type实例的请求,而不是SeededRequest ,因为几乎所有的SeededRequest值都被中继到Type对象的请求:

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