使用AutoFixture创建递归树
我刚刚开始使用AutoFixture并拥有这个半复杂的数据结构,我想创建一些标本。 在我正在进行的测试中,我不太关心数据结构的内容。 我只想要合理的默认值。
此数据结构的一部分是递归树。 更具体地说,一个类包含一些其他类的集合,其中包含自身的子列表。 类似于:
public class A { private IEnumerable bNodes; public A(IEnumerable bNodes) { this.bNodes = bNodes; } } public class B { private IEnumerable children; public B(IEnumerable children) { this.children = children; } }
让我们假设我不能因各种原因轻易改变这种结构。
如果我要求我的夹具创建一个ThrowingRecursionBehavior将开始咆哮B是递归的。
如果我用OmitOnRecursionBehavior替换ThrowingRecursionBehavior,我会得到一个ObjectCreateException。
如果我尝试类似:fixture.Inject(Enumerable.Empty()); 我从DictionaryFiller获得“已添加相同键的项目”。 如果我用NullRecursionBehavior替换ThrowingRecursionBehavior,也会发生同样的事情。
我想要几件事。
- 用空的B列表创建A样本的最佳方法是什么?
- 创建一个A标本的最佳方法是什么,其中包含一些含有少数几个孩子(一棵小树)的B孩子的B?
对于我的遗愿,指定一些递归深度可能会很好,之后使用Enumerable.Empty(或零大小的数组/ List或甚至为null)。 我知道AutoFixture可以非常灵活地扩展。 因此,我认为应该可以创建一些完全符合这一要求的样本构建器。 事实上,我会尝试使用自定义的ISpecimenBuilder,但也许有人已经拥有了一个更智能的解决方案。 例如,在RecursionGuard中修改此行是否有意义:
public object Create(object request, ISpecimenContext context) { if (this.monitoredRequests.Any(x => this.comparer.Equals(x, request))) ...
至
public object Create(object request, ISpecimenContext context) { if (this.monitoredRequests.Count(x => this.comparer.Equals(x, request)) > maxAllowedRecursions) ...
使用空的B列表创建A.
使用空的B列表创建A的实例很容易:
var fixture = new Fixture(); fixture.Inject(Enumerable.Empty()); var a = fixture.Create();
创建一个小树
创建一棵小树要困难得多,但这是可能的。 你已经开始考虑RecursionGuard
。 为了validation这是否可行,我从RecursionGuard
复制了大部分代码并创建了这个DepthRecursionGuard
作为概念certificate :
public class DepthRecursionGuard : ISpecimenBuilderNode { private readonly ISpecimenBuilder builder; private readonly Stack
请注意Create
方法的更改实现,以及HandleRecursiveRequest
中IEnumerable
的特定处理。
为了使其可以从Fixture
实例中使用,我还添加了这个DepthRecursionBehavior
:
public class DepthRecursionBehavior : ISpecimenBuilderTransformation { public ISpecimenBuilder Transform(ISpecimenBuilder builder) { return new DepthRecursionGuard(builder); } }
这使我能够创建一个小树:
var fixture = new Fixture(); fixture.Behaviors.OfType() .ToList().ForEach(b => fixture.Behaviors.Remove(b)); fixture.Behaviors.Add(new DepthRecursionBehavior()); var a = fixture.Create();
虽然这是可能的,但在我看来,这太难了,所以我创建了一个工作项 ,以便将来更容易。
更新2013.11.13:从AutoFixture 3.13.0开始,可以通过该API配置递归深度。