AutoFixture 在复杂对象中创建不需要的深度

Ala*_*SFT 5 c# autofixture entity-framework-6

我有一个来自 EF6(数据库优先)的复杂图表,我想在测试域模型时使用模拟和测试装置进行模拟。为了防止循环依赖问题,我将这些行添加到测试设置中:

private Fixture _fixture;
public WhenRetrievingPlans()
{
    _fixture = new Fixture();
    _fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
                            .ForEach(b => _fixture.Behaviors.Remove(b)); 
    _fixture.Behaviors.Add(new OmitOnRecursionBehavior());
    using (var writer = new StreamWriter(@"D:\Workspace\Project\source\Project.Model.Test\trace.txt"))
    {
        _fixture.Behaviors.Add(new TracingBehavior(writer));
Run Code Online (Sandbox Code Playgroud)

然后我尝试阻止夹具尝试将对象图追至遗忘,并创建一个没有任何子对象的简单对象,如下所示:

        _fixture.Build<EntityType>()
            .Without(e => e.ObjectProperty1)
            .Without(e => e.ObjectProperty2)
            .Without(e => e.CollectionProperty3)
            .Without(e => e.CollectionProperty4)
            .Without(e => e.ObjectProperty5)
            ...
            .Create();
Run Code Online (Sandbox Code Playgroud)

这样就不会创建作为此 EntityType 属性的对象或集合。其余属性是简单类型,包括一些 Nullable 和 DateTime 值以及 Int32 和 String 类型。

我想让 AutoFixture 创建 EntityType 的实例,然后我计划从模拟返回该实例。(这可能不相关。)

        var entitiesDbSetMock = new Mock<IDbSet<EntityType>>();
        entitiesDbSetMock.SetupAllProperties();
        _fixture.Inject<IDbSet<EntityType>>(entitiesDbSetMock.Object);
Run Code Online (Sandbox Code Playgroud)

然后我将对象添加到这个 Mock 中:

        var entity = _fixture.Create<EntityType>();
        entitiesDbSetMock.Object.Attach(entity);
Run Code Online (Sandbox Code Playgroud)

问题是这样的:AutoFixture 并没有阻止自己生成可以从此 EntityType 访问的每个可能的对象,即使使用了.Without()我使用的所有操作。我怎么知道?因为我开启了追踪功能。仅对于这一个创建操作,就生成了近 750,000 行跟踪(这是一个 100MB 的文件)。

在阅读跟踪时,第一部分显示了 EntityType 的创建以及我未排除的所有属性的设置。但是在该东西被创建之后,它似乎又被创建了,但这一次它忽略了我的Without()自定义,并且深入。

Requested: Ploeh.AutoFixture.Kernel.SeededRequest
  Requested: Project.Data.EntityType
    Requested: Int32 EntityTypeID
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: System.Int32
        Created: 232
      Created: 232
    Created: 232
    Requested: System.Nullable`1[System.Int32] ForeignKey1ID
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: System.Nullable`1[System.Int32]
          Requested: Int32 value
            Requested: Ploeh.AutoFixture.Kernel.SeededRequest
              Requested: System.Int32
              Created: 224
            Created: 224
          Created: 224
        Created: 224
      Created: 224
    Created: 224
    Requested: Int32 Property2ID
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: System.Int32
        Created: 40
      Created: 40
    Created: 40
    Requested: System.DateTime Property3Date
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: System.DateTime
        Created: 6/6/2014 4:05:24 PM
      Created: 6/6/2014 4:05:24 PM
    Created: 6/6/2014 4:05:24 PM
    *... (similar lines elided for brevity)*
    Requested: Project.Data.OtherEntity OtherEntity
    Created: Ploeh.AutoFixture.Kernel.OmitSpecimen
    Requested: Project.Data.YetAnotherEntity YetAnotherEntity
    Created: Ploeh.AutoFixture.Kernel.OmitSpecimen
    Requested: System.Collections.Generic.ICollection`1[Project.Data.CollectionEntity] CollectionEntities
    Created: Ploeh.AutoFixture.Kernel.OmitSpecimen
    *... (similar lines elided for brevity)*
  Created: Project.Data.EntityType
Created: Project.Data.EntityType
Run Code Online (Sandbox Code Playgroud)

就在那里,我希望跟踪能够完成。对象被创建了,正是我想要的。但它并不止于此。紧接着,我看到 AutoFixture 继续运行。

Requested: Ploeh.AutoFixture.Kernel.SeededRequest
  Requested: Project.Data.YetAnotherEntity
  Created: Project.Data.YetAnotherEntity
Created: Project.Data.YetAnotherEntity
Requested: Ploeh.AutoFixture.Kernel.SeededRequest
  Requested: Project.Data.UnrelatedEntity
  Created: Project.Data.UnrelatedEntity
Created: Project.Data.UnrelatedEntity
Requested: Ploeh.AutoFixture.Kernel.SeededRequest
  Requested: Project.Data.EntityType  *<<-- Again? We did this already.*
    Requested: Int32 EntityTypeID
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: System.Int32
        Created: 107
      Created: 107
    Created: 107
    Requested: System.Nullable`1[System.Int32] ForeignKey1ID
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: System.Nullable`1[System.Int32]
          Requested: Int32 value
            Requested: Ploeh.AutoFixture.Kernel.SeededRequest
              Requested: System.Int32
              Created: 87
            Created: 87
          Created: 87
        Created: 87
      Created: 87
    Created: 87
    Requested: Int32 Property2ID
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: System.Int32
        Created: 105
      Created: 105
    Created: 105
    Requested: System.DateTime Property3Date
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: System.DateTime
        Created: 5/31/2014 6:50:10 PM
      Created: 5/31/2014 6:50:10 PM
    Created: 5/31/2014 6:50:10 PM
    Requested: Project.Data.OtherEntity OtherEntity  *<<!! NO! I stopped you!*
      Requested: Ploeh.AutoFixture.Kernel.SeededRequest
        Requested: Project.Data.OtherEntity
          Requested: Int32 ForeignKey1ID
            Requested: Ploeh.AutoFixture.Kernel.SeededRequest
              Requested: System.Int32
              Created: 168
            Created: 168
          Created: 168
          Requested: System.String Name
            Requested: Ploeh.AutoFixture.Kernel.SeededRequest
              Requested: System.String
              Created: 61eb26e3-890d-4d0d-badd-cd3467c299ed
            Created: Name61eb26e3-890d-4d0d-badd-cd3467c299ed
          Created: Name61eb26e3-890d-4d0d-badd-cd3467c299ed
          Requested: Int32 OtherEntityID
            Requested: Ploeh.AutoFixture.Kernel.SeededRequest
              Requested: System.Int32
              Created: 187
            Created: 187
          Created: 187
*... and on and on for 750,000 more lines.
Run Code Online (Sandbox Code Playgroud)

当然,这个东西可能有各种代码味道,而且我知道 Mark Seemann 对 EF 或任何其他 ORM 并不感兴趣。但我认为它应该有效,而且我不知道我错过了什么。

Ala*_*SFT 2

现在,我更仔细地查看了这些示例,以便回答 Mark 的评论(谢谢你,Mark!!)...我看到 Build 方法有一个 T 类型的返回值。(拍拍额头)

所以现在我发现我认为 Build 所做的事情是错误的。它实际上在那里实例化了一个 T 。我怀疑我需要做的(创建模板)是扩展 SpecimenBuilder 并以某种方式注册它,方法是将其添加到设置夹具的自定义/自定义序列中。

马克,如果你想留下更好的答案,我会等一两天,然后选择你的答案作为正确答案。

  • 您对“Build&lt;T&gt; .. Create()”方法链的看法是正确的。请查看“Customize&lt;T&gt;”方法。这里有一个简单的例子,最后:http://stackoverflow.com/a/16457857/126014 (2认同)
  • 也许“Customize&lt;T&gt;”的一个更好的例子是这个:https://github.com/AutoFixture/AutoFixture/wiki/Cheat-Sheet#customize-type (2认同)