AutoFixture:配置开放式仿制标本生成器 [英] AutoFixture: Configuring an Open Generics Specimen Builder

查看:224
本文介绍了AutoFixture:配置开放式仿制标本生成器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  public interface IOGF< T> 
{
}

class C
{
}

class D
{
只读IOGF< c取代; _ogf;

public D(IOGF< C> ogf)
{
_ogf = ogf;




$ b我试图让AutoFixture生成匿名实例上面的 D 。但是,AutoFixture本身没有构建 IOGF<> 的内置策略,因此我们观察到:

  public class OpenGenericsBinderDemo 
{
[Fact]
public void X()
{
var fixture =新的Fixture(); $(b)b
$ b Assert.Throws< Ploeh.AutoFixture.ObjectCreationException>(()=>
fixture.CreateAnonymous< D>);

$ / code>

基本信息是:


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


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

  public class OGF< T> :IOGF< T> 
{
public OGF(IX x)
{
}
}

公共接口IX
{
}

public class X:IX
{
}

和一个关联的绑定:

  fixture.Register< IX,X>(); 

我如何(或者我应该怎么看待这个问题?)做下面的测试()

  public class OpenGenericsLearning 
{
[Fact]
public void OpenGenericsDontGetResolved()
{
var fixture = new Fixture(); (b)。fixture.ject< IX>(fixture.Freeze< X>());

// TODO注册或做一些提供
// OGF< C>以满足D的IOGF C< C>要求

Assert.NotNull(fixture.CreateAnonymous< D>);;


$ / code $ / pre
$ b $(有关于codeplex的讨论和问题网站 - 我只是需要一个快速实现这一点,并打算删除这个,如果这只是一个坏主意和/或我错过了什么)



编辑2 :(参见马克答案的评论)这里的(被承认设计的)上下文是对一个大的几乎完整的系统System Under Test对象图的验收测试,而不是一个小的(受控/易于理解:)对或三重类在单元或集成测试场景中。正如在自问题括号声明中所暗示的那样,我并不完全相信这种类型的测试甚至是合理的。

解决方案

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

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

这篇关于AutoFixture:配置开放式仿制标本生成器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆