AutoFixture:配置开放式泛型样本生成器(AutoFixture: Configuring

2019-06-23 12:52发布

我有一个使用泛型开放(是的,是的,现在我有两个问题,一个对象模型,这就是为什么我在这里:): -

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无法创建IOGF`1 [C]的实例,很可能是因为它没有公共的构造,是一个抽象的,非公开的类型。

我很高兴地提供它的具体实现:

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上现场讨论和问题,解决这个 - 我只是需要这种快速IMPL并愿意接受删除此,如果这仅仅是一个坏主意和/或我错过了什么)

编辑2:(参见马克的回答也评论)(公认做作)这里的上下文是一个大“几乎全系统”系统验收测试,在测试对象图,而不是一个小的(控制/易神交:)对或三重在一个单元或集成测试场景类。 作为在自问题括号声明提到,我并不完全相信这种类型的测试,即使是有道理的,但。

Answer 1:

你可以创建其工作原理如下自定义:

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


Answer 2:

AFICT有看不到打开的仿制药。 D依赖于IOGF<C>这是一个构造类型。

该错误消息是因为开放泛型的,而是因为IOGF<C>是一个接口。

你可以提供一个映射从IOGF<C>OGF<C>是这样的:

fixture.Register<IOGF<C>>(() => fixture.CreateAnonymous<OGF<C>>());

由于OGF<C>依赖于IX你还需要提供一个映射到X

fixture.Register<IX>(() => fixture.CreateAnonymous<X>());

这应该够了吧。

然而,随着尼科斯Baxevanis在他的评论中指出,如果使用三提供的自动嘲讽扩展之一,这将主要工作,开箱即用 - 例如,

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


文章来源: AutoFixture: Configuring an Open Generics Specimen Builder