如何在 AutoFixture 中设置更复杂(类似 IoC)的注册
How to setup more complicated (IoC like) registration in AutoFixture
使用 AutoFixture 时是否可以在集成测试中重用生产 IoC 容器注册?
问题是,如果依赖项未注册并注入 "real" 数据库相关依赖项,我需要以下夹具设置来注入模拟
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<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);
}
}
但这种方法的问题是 container.Resolve
不会考虑已在 AutoFixture 中注册的依赖项。
是否有任何其他方法可以解决这个问题以进行更复杂的注册?
一般方法看起来不错,但您应该将 ContainerSpecimenBuilder
添加到 ResidueCollectors
而不是 Customizations
:
fixture.ResidueCollectors.Add(new ContainerSpecimenBuilder(containerBuilder.Build()));
AutoMoqCustomization
还向 ResidueCollectors
添加了一个节点,因此您可能需要对特定的顺序进行一些试验,以弄清楚如何使其表现得像您希望的那样。 The ordering matters.
有关 Customizations
和 ResidueCollectors
之间差异的更多信息,请参阅 AutoFixture architecture documentation。
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);
}
}
使用 AutoFixture 时是否可以在集成测试中重用生产 IoC 容器注册?
问题是,如果依赖项未注册并注入 "real" 数据库相关依赖项,我需要以下夹具设置来注入模拟
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<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);
}
}
但这种方法的问题是 container.Resolve
不会考虑已在 AutoFixture 中注册的依赖项。
是否有任何其他方法可以解决这个问题以进行更复杂的注册?
一般方法看起来不错,但您应该将 ContainerSpecimenBuilder
添加到 ResidueCollectors
而不是 Customizations
:
fixture.ResidueCollectors.Add(new ContainerSpecimenBuilder(containerBuilder.Build()));
AutoMoqCustomization
还向 ResidueCollectors
添加了一个节点,因此您可能需要对特定的顺序进行一些试验,以弄清楚如何使其表现得像您希望的那样。 The ordering matters.
有关 Customizations
和 ResidueCollectors
之间差异的更多信息,请参阅 AutoFixture architecture documentation。
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);
}
}