AutoFixture可以省略类层次结构之间的递归吗?

时间:2018-01-25 08:53:05

标签: abstract-class autofixture

考虑以下表示家庭成员的方式:

public abstract class Human { }
public abstract class Child : Human
{
    public ICollection<Parent> Parents { get; set; }
}
public abstract class Parent : Human
{
    public ICollection<Child> Children { get; set; }
}
public class Son : Child { }
public class Daughter : Child { }
public class Mum : Parent { }
public class Dad : Parent { }

现在,我希望AutoFixture生成一个Parent,在MumDad之间随机选择,并在SonDaughter之间随机选择Parent。我也希望它省略递归,所以如果它来自Child并生成Parent,它可以省略回到var fixture = new Fixture(); fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList() .ForEach(b => fixture.Behaviors.Remove(b)); fixture.Behaviors.Add(new OmitOnRecursionBehavior()); var random = new Random(); fixture.Register<Parent>(() => { switch (random.Next(1, 2)) { case 1: return fixture.Create<Mum>(); case 2: return fixture.Create<Dad>(); default: throw new NotImplementedException(); } }); fixture.Register<Child>(() => { switch (random.Next(1, 2)) { case 1: return fixture.Create<Son>(); case 2: return fixture.Create<Daughter>(); default: throw new NotImplementedException(); } }); fixture.Create<Parent>(); 的链接。

我尝试了以下自定义:

InvalidCastException

但它会抛出一个Parent -> Child -> Parent(见下文)。

有没有办法配置AutoFixture以便它考虑Unhandled Exception: AutoFixture.ObjectCreationExceptionWithPath: AutoFixture was unable to create an instance from AutoFixtureAbstractTrees.Parent because creation unexpectedly failed with exception. Please refer to the inner exception to investigate the root cause of the failure. Request path: AutoFixtureAbstractTrees.Mum System.Collections.Generic.ICollection`1[AutoFixtureAbstractTrees.Child] Children System.Collections.Generic.ICollection`1[AutoFixtureAbstractTrees.Child] System.Collections.Generic.List`1[AutoFixtureAbstractTrees.Child] System.Collections.Generic.IEnumerable`1[AutoFixtureAbstractTrees.Child] collection System.Collections.Generic.IEnumerable`1[AutoFixtureAbstractTrees.Child] AutoFixtureAbstractTrees.Child AutoFixtureAbstractTrees.Son System.Collections.Generic.ICollection`1[AutoFixtureAbstractTrees.Parent] Parents System.Collections.Generic.ICollection`1[AutoFixtureAbstractTrees.Parent] System.Collections.Generic.List`1[AutoFixtureAbstractTrees.Parent] System.Collections.Generic.IEnumerable`1[AutoFixtureAbstractTrees.Parent] collection System.Collections.Generic.IEnumerable`1[AutoFixtureAbstractTrees.Parent] AutoFixtureAbstractTrees.Parent Inner exception messages: System.InvalidCastException: Unable to cast object of type 'AutoFixture.Kernel.OmitSpecimen' to type 'AutoFixtureAbstractTrees.Mum'. 递归,即使它实际上为每个实例随机选择了一个合适的子类?

catch

1 个答案:

答案 0 :(得分:1)

您遇到此问题的原因是因为AutoFixture中存在设计缺陷。当你使用ISpecimenBuilder扩展方法时,你基本上启动了一个新的解决方案上下文,而递归防护机制并没有抓住它。

看起来,在这种情况下,您可以使用Resolve中的contextCreate来解决问题,而不是使用[Fact] public void WorkAround() { var fixture = new Fixture(); fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList() .ForEach(b => fixture.Behaviors.Remove(b)); fixture.Behaviors.Add(new OmitOnRecursionBehavior(3)); var random = new Random(); fixture.Customizations.Add(new ParentBuilder(random)); fixture.Customizations.Add(new ChildBuilder(random)); var actual = fixture.Create<Parent>(); Assert.True(0 < actual.Children.Count); } 扩展方法:< / p>

ParentBuilder

此测试通过,并使用自定义类ChildBuilderpublic class ParentBuilder : ISpecimenBuilder { private readonly Random random; public ParentBuilder(Random random) { this.random = random; } public object Create(object request, ISpecimenContext context) { var t = request as Type; if (t == null || t != typeof(Parent)) return new NoSpecimen(); if (this.random.Next(0, 2) == 0) return context.Resolve(typeof(Mum)); else return context.Resolve(typeof(Dad)); } } public class ChildBuilder : ISpecimenBuilder { private readonly Random random; public ChildBuilder(Random random) { this.random = random; } public object Create(object request, ISpecimenContext context) { var t = request as Type; if (t == null || t != typeof(Child)) return new NoSpecimen(); if (this.random.Next(0, 2) == 0) return context.Resolve(typeof(Son)); else return context.Resolve(typeof(Daughter)); } }

require

所有这一切,作为you've previously discovered,你在这里推动了AutoFixture的限制。它并非真正用于处理复杂的递归对象设计,如此处所示。