10

Open Generics を使用するオブジェクト モデルがあります (はい、はい、2 つの問題があります。それが私がここにいる理由です :) :-

public interface IOGF<T>
{
}

class C
{
}

class D
{
    readonly IOGF<C> _ogf;

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

AutoFixture にD上記の Anonymous インスタンスを生成させようとしています。ただし、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 サイトにあります - 私はこれを簡単に実装する必要があり、これが単に悪い考えである場合、および/または何かを見逃した場合は、これを削除してもかまいません)

EDIT 2: (マークの回答に関するコメントも参照してください) ここでの (明らかに不自然な) コンテキストは、小さな (制御された/理解しやすい :) ペアまたはトリプレットではなく、大規模な「ほぼ完全なシステム」テスト対象システム オブジェクト グラフの受け入れテストです。ユニットまたは統合テスト シナリオのクラスの。自問自答の括弧内の文で暗示されているように、私はこの種のテストが理にかなっていると完全に確信しているわけではありません.

4

2 に答える 2

9

次のように機能するカスタマイズを作成できます。

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; }
    }
}
于 2012-04-10T16:17:01.473 に答える
4

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>());

これでうまくいくはずです。

ただし、Nikos Baxevanis がコメントで指摘しているように、提供されている 3 つの自動モック拡張機能のいずれかを使用する場合、これは基本的にそのままで動作します。

var fixture = new Fixture().Customize(new AutoMoqCustomization());
var d = fixture.CreateAnonymous<D>();
于 2012-04-10T18:45:22.590 に答える