C# AutoFixture:配置开放式泛型样本生成器

C# AutoFixture:配置开放式泛型样本生成器,c#,generics,autofixture,open-generics,C#,Generics,Autofixture,Open Generics,我有一个使用开放泛型的对象模型(是的,是的,现在我有两个问题;这就是我在这里的原因:):- 基本信息是: Ploeh.AutoFixture.ObjectCreationException:AutoFixture无法从IOGF`1[C]创建实例,很可能是因为它没有公共构造函数,是抽象或非公共类型 我很高兴为它提供一个具体的实现: public class OGF<T> : IOGF<T> { public OGF( IX x ) { } } pu

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

基本信息是:

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

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

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

public interface IX
{
}

public class X : IX
{
}
公共类OGF:IOGF
{
公共OGF(IX x)
{
}
}
公共接口九
{
}
公共类别X:IX
{
}
以及相关的绑定:

fixture.Register<IX,X>();
fixture.Register();
我如何(或者我应该这样看待问题??)通过以下测试

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>());
    }
}
公共类OpenGenericsLearning
{
[事实]
public void OpenGenericsDontGetResolved()
{
var fixture=新fixture();
fixture.Inject(fixture.Freeze());
//TODO注册或执行将提供
//OGF满足D的IOGF要求
Assert.NotNull(fixture.CreateAnonymous());
}
}
(在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 );
    }
}
我假设有人有一个更好的实现,尽管和/或有一个内置的实现

编辑:以下是使用传感属性更新的D:

class D
{
    readonly IOGF<C> _ogf;

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

    public IOGF<C> Ogf
    {
        get { return _ogf; }
    }
}
D类
{
只读IOGF_ogf;
公共事务主任
{
_ogf=ogf;
}
公共组织
{
获取{return\u ogf;}
}
}

AFICT目前还看不到开放的泛型
D
依赖于构造类型的
IOGF

错误消息不是因为开放泛型,而是因为
IOGF
是一个接口

您可以从
IOGF
OGF
提供如下内容:

fixture.Register<IOGF<C>>(() => fixture.CreateAnonymous<OGF<C>>());
这应该能奏效

然而,正如Nikos Baxevanis在他的评论中指出的那样,如果您使用提供的三个自动模拟扩展中的一个,这基本上是开箱即用的-例如

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

AutoMoq、AutoHinoMocks和AutoFakeiTesy是允许您将AutoFixture用作自动模拟容器的扩展。这是一种选择吗?(因为这样你就可以成功地创建一个匿名的D实例。)@Nikos我知道自动模拟的扩展,并且在精神上排除了它们——应该提到这一点;有关更多背景信息,请参见我对马克答案的评论)。把这句话和马克的回答放在心上,我将加倍努力避免依赖我的拐杖!相关:@RubenBartelink好奇,这个开放的通用代码用于什么?我喜欢人们使用开放泛型来解决问题,但泛型的C#不规则类型系统,带有角案例和gotchas,有时让我觉得付出的努力不值得。@JohnZabroski Ha,我现在不记得了-使用一些泛型存储库反模式测试东西+谢谢你,马克。我猜这个问题有点做作,我没有投入足够的精力使它可信。我的目的是希望能够匹配DI框架(和约定扩展)的开放泛型绑定功能。这源于我/我们在验收和集成测试中大量使用AF这一事实,其中构建各种复杂上下文类和帮助程序的能力非常突出(但也是过于复杂测试的一个滑动斜率)。您的观点很清楚,在任何合理的单元测试中都不需要这样的绑定。(我知道您引用的大部分内容,并且同意不无偿提供重载的设计决策(例如,
Register
)这需要一个`类型,这可能会使它更整洁。实际问题可能会通过重新设计存在此需求的测试上下文类/装置来解决。我得到一个异常:System.ArgumentException:类型为'Ploeh.AutoFixture.Kernel.OmitExample'的对象无法转换为类型'SelogerCity.Data.Entit'ies.User'。如果使用上述自定义.Type,则应为ISet或IList…要使此库变得有用,需要做大量工作。@Sam抱歉,直到现在才看到此内容。您的测试失败了吗?(我最终使用了这段代码,到目前为止它已经满足了我的需求,但我不知道你在做什么,因此无法真正开始猜测我的代码中的哪一个强制转换或比较需要改进)太棒了,在Rx库中的
IObservable->Subject
中按预期工作
class D
{
    readonly IOGF<C> _ogf;

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

    public IOGF<C> Ogf
    {
        get { return _ogf; }
    }
}
fixture.Register<IOGF<C>>(() => fixture.CreateAnonymous<OGF<C>>());
fixture.Register<IX>(() => fixture.CreateAnonymous<X>());
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var d = fixture.CreateAnonymous<D>();