AutoFixture:配置Open Generics Specimen Builder

我有一个使用Open Generics的对象模型(是的,是的,现在我有两个问题;这就是为什么我在这里:): –

public interface IOGF { } class C { } class D { readonly IOGF _ogf; public D( IOGF ogf ) { _ogf = ogf; } } 

我正在尝试让AutoFixture生成上面的D匿名实例。 然而,就其本身而言,AutoFixture没有构建IOGF的内置策略,因此我们观察到:

 public class OpenGenericsBinderDemo { [Fact] public void X() { var fixture = new Fixture(); Assert.Throws( () => fixture.CreateAnonymous() ); } 

基本信息是:

Ploeh.AutoFixture.ObjectCreationException:AutoFixture无法从IOGF`1 [C]创建实例,很可能是因为它没有公共构造函数,是抽象或非公共类型。

我很高兴为它提供一个具体的实现:

 public class OGF : IOGF { public OGF( IX x ) { } } public interface IX { } public class X : IX { } 

以及相关的绑定:

 fixture.Register(); 

我如何(或者我应该以这种方式查看问题?)使以下测试通过?

 public class OpenGenericsLearning { [Fact] public void OpenGenericsDontGetResolved() { var fixture = new Fixture(); fixture.Inject( fixture.Freeze() ); // TODO register or do something that will provide // OGF to fulfill D's IOGF requirement Assert.NotNull( fixture.CreateAnonymous()); } } 

(在codeplex网站上有关于此问题的讨论和问题 – 我只需要快速了解这一点,如果这只是一个坏主意和/或我错过了某些内容,我可以删除它

编辑2 :(另请参阅Mark的回答评论)这里(公认的设计)上下文是对一个大的“几乎完整的系统”系统测试对象图而不是一个小的(受控/易于理解:)对或三元组的验收测试单元或集成测试场景中的类。 正如在自我问题括号中所提到的那样,我并不完全相信这种类型的测试甚至有意义。

您可以创建一个自定义,其工作方式如下:

 public class AnOpenGenericsBinderDemo { [Fact] public void RegisteringAGenericBinderShouldEnableResolution() { var fixture = new Fixture(); fixture.Inject( fixture.Freeze() ); fixture.RegisterOpenGenericImplementation( typeof( IOGF<> ), typeof( OGF<> ) ); Assert.IsType>( fixture.CreateAnonymous().Ogf ); } } 

并实现如下:

 public static class AutoFixtureOpenGenericsExtensions { public static void RegisterOpenGenericImplementation( this IFixture that, Type serviceType, Type componentType ) { if ( !serviceType.ContainsGenericParameters ) throw new ArgumentException( "must be open generic", "serviceType" ); if ( !componentType.ContainsGenericParameters ) throw new ArgumentException( "must be open generic", "componentType" ); // TODO verify number of type parameters is 1 in each case that.Customize( new OpenGenericsBinderCustomization( serviceType, componentType ) ); } public class OpenGenericsBinderCustomization : ICustomization { readonly Type _serviceType; readonly Type _componentType; public OpenGenericsBinderCustomization( Type serviceType, Type componentType ) { _serviceType = serviceType; _componentType = componentType; } void ICustomization.Customize( IFixture fixture ) { fixture.Customizations.Add( new OpenGenericsSpecimenBuilder( _serviceType, _componentType ) ); } class OpenGenericsSpecimenBuilder : ISpecimenBuilder { readonly Type _serviceType; readonly Type _componentType; public OpenGenericsSpecimenBuilder( Type serviceType, Type componentType ) { _serviceType = serviceType; _componentType = componentType; } object ISpecimenBuilder.Create( object request, ISpecimenContext context ) { var typedRequest = request as Type; if ( typedRequest != null && typedRequest.IsGenericType && typedRequest.GetGenericTypeDefinition() == _serviceType ) return context.Resolve( _componentType.MakeGenericType( typedRequest.GetGenericArguments().Single() ) ); return new NoSpecimen( request ); } } } } 

我假设某人有比这更好的实现和/或有内置实现。

编辑:以下是具有感知属性的更新D:

 class D { readonly IOGF _ogf; public D( IOGF ogf ) { _ogf = ogf; } public IOGF Ogf { get { return _ogf; } } } 

AFICT看不到开放的仿制药。 D依赖于IOGF ,它是一种构造类型。

错误消息不是因为开放的generics,而是因为IOGF是一个接口。

您可以提供从IOGFOGF 的映射 ,如下所示:

 fixture.Register>(() => fixture.CreateAnonymous>()); 

由于OGF依赖于IX您还需要提供到X的映射:

 fixture.Register(() => fixture.CreateAnonymous()); 

这应该够了吧。

但是,正如Nikos Baxevanis在评论中指出的那样,如果你使用三个提供的自动模拟扩展中的一个,这基本上可以开箱即用 – 例如

 var fixture = new Fixture().Customize(new AutoMoqCustomization()); var d = fixture.CreateAnonymous();