我有一个使用Open Generics的对象模型(是的,是的,现在我有两个问题;这就是为什么我在这里:): –
public interface IOGF<T> { } class C { } class D { readonly IOGF<C> _ogf; public D( IOGF<C> ogf ) { _ogf = ogf; } }
我正在尝试让AutoFixture生成上面的D的匿名实例.然而,就其自身而言,AutoFixture没有用于构建IOGF的内置策略<>因此我们观察到:
public class OpenGenericsBinderDemo { [Fact] public void X() { var fixture = new Fixture(); Assert.Throws<Ploeh.AutoFixture.ObjectCreationException>( () => fixture.CreateAnonymous<D>() ); }
基本信息是:
Ploeh.AutoFixture.ObjectCreationException : AutoFixture was unable to create an instance from IOGF`1[C],most likely because it has no public constructor,is an abstract or non-public type.
我很高兴为它提供一个具体的实现:
public class OGF<T> : IOGF<T> { public OGF( IX x ) { } } public interface IX { } public class X : IX { }
以及相关的绑定:
fixture.Register<IX,X>();
我如何(或者我应该以这种方式查看问题?)使以下测试通过?
public class OpenGenericsLearning { [Fact] public void OpenGenericsDontGetResolved() { var fixture = new Fixture(); fixture.Inject<IX>( fixture.Freeze<X>() ); // TODO register or do something that will provide // OGF<C> to fulfill D's IOGF<C> requirement Assert.NotNull( fixture.CreateAnonymous<D>()); } }
(在codeplex网站上有关于此问题的讨论和问题 – 我只需要快速了解这一点,如果这只是一个坏主意和/或我错过了某些内容,我可以删除它
编辑2 :(另请参阅Mark的回答评论)这里(公认的设计)上下文是对一个大的“几乎完整的系统”系统测试对象图而不是一个小的(受控/易于理解:)对或三元组的验收测试单元或集成测试场景中的类.正如在自我问题括号中所提到的那样,我并不完全相信这种类型的测试甚至有意义.
解决方法
您可以创建一个自定义,其工作方式如下:
public class AnOpenGenericsBinderDemo { [Fact] public void RegisteringAGenericBinderShouldEnableResolution() { var fixture = new Fixture(); fixture.Inject<IX>( fixture.Freeze<X>() ); fixture.RegisterOpenGenericImplementation( typeof( IOGF<> ),typeof( OGF<> ) ); Assert.IsType<OGF<C>>( fixture.CreateAnonymous<D>().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<C> _ogf; public D( IOGF<C> ogf ) { _ogf = ogf; } public IOGF<C> Ogf { get { return _ogf; } } }