更新时间:2023-09-23 11:34:04
您可以创建一个自定义,其工作原理如下:
public class AnOpenGenericsBinderDemo
{
[Fact]
public void RegisteringGenericBinderShouldEnableResolution()
{
var fixture = new Fixture(); (b)。fixture.ject< IX>(fixture.Freeze< X>()); $ type(OGF<>));
Assert.IsType< OGF< C>>(fixture.CreateAnonymous< D>).Ogf;
$ b 并且这样执行:
public static class AutoFixtureOpenGenericsExtensions
{
public static void RegisterOpenGenericImplementation(this IFixture that,Type serviceType,Type componentType)
{
if(!serviceType.ContainsGenericParameters)
throw new ArgumentException(must open generic,serviceType);
if(!componentType.ContainsGenericParameters)
throw new ArgumentException(must open generic,componentType);
// TODO验证每种情况下类型参数的数量为1
that.Customize(new OpenGenericsBinderCustomization(serviceType,componentType));
}
公共类OpenGenericsBinderCustomization:ICustomization
{
只读类型_serviceType;
只读类型_componentType;
public OpenGenericsBinderCustomization(类型serviceType,类型componentType)
{
_serviceType = serviceType;
_componentType = componentType;
}
void ICustomization.Customize(IFixture fixture)
{
fixture.Customizations.Add(new OpenGenericsSpecimenBuilder(_serviceType,_componentType));
}
类OpenGenericsSpecimenBuilder:ISpecimenBuilder
{
只读类型_serviceType;
只读类型_componentType;
public OpenGenericsSpecimenBuilder(类型serviceType,类型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 ()));
返回新的NoSpecimen(请求);
}
}
}
}
I编辑:下面是带感应属性的更新D:
编辑: p>
class D
{
只读IOGF< C> _ogf;
public D(IOGF< C> ogf)
{
_ogf = ogf;
}
public IOGF< C> Ogf
{
get {return _ogf; }
}
}
I have an object model that uses Open Generics (Yes, yes, now I have two problems; that's why I'm here :) :-
public interface IOGF<T>
{
}
class C
{
}
class D
{
readonly IOGF<C> _ogf;
public D( IOGF<C> ogf )
{
_ogf = ogf;
}
}
I'm trying to get AutoFixture to generate Anonymous instances of D
above. However, on its own, AutoFixture doesn't have a built in strategy for building an IOGF<>
and hence we observe:
public class OpenGenericsBinderDemo
{
[Fact]
public void X()
{
var fixture = new Fixture();
Assert.Throws<Ploeh.AutoFixture.ObjectCreationException>( () =>
fixture.CreateAnonymous<D>() );
}
The underlying message is:
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.
I'm happy to provide it a concrete implementation:
public class OGF<T> : IOGF<T>
{
public OGF( IX x )
{
}
}
public interface IX
{
}
public class X : IX
{
}
And an associated binding:
fixture.Register<IX,X>();
How do I (or should I even look at the problem that way??) make the following test pass?
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>());
}
}
(There are discussions and issues around this on the codeplex site - I just needed to a quick impl of this and am open to deleting this if this is just a bad idea and/or I've missed something)
EDIT 2: (See also comment on Mark's answer) The (admittedly contrived) context here is an acceptance test on a large 'almost full system' System Under Test object graph rather than a small (controlled/easy to grok :) pair or triplet of classes in a unit or integration test scenario. As alluded to in the self-question parenthetical statement, I'm not fully confident this type of test even makes sense though.
You could create a customization which works as follows:
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 );
}
}
And is implemented like so:
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 );
}
}
}
}
I assume someone has a better implementation than that though and/or there is a built-in implementation.
EDIT: The following is the updated D with the sensing property:
class D
{
readonly IOGF<C> _ogf;
public D( IOGF<C> ogf )
{
_ogf = ogf;
}
public IOGF<C> Ogf
{
get { return _ogf; }
}
}