C# 用AutoFixture创建递归树

C# 用AutoFixture创建递归树,c#,unit-testing,autofixture,C#,Unit Testing,Autofixture,我刚刚开始使用AutoFixture,并且有这个半复杂的数据结构,我想为它创建一些样本。 在我正在进行的测试中,我不太关心数据结构的内容。我只想要合理的默认值 此数据结构的一部分是递归树。更具体地说,一个类包含另一个类的集合,该集合包含它自己的子类列表。 类似于: public class A { private IEnumerable<B> bNodes; public A(IEnumerable<B> bNodes) { this.bNo

我刚刚开始使用AutoFixture,并且有这个半复杂的数据结构,我想为它创建一些样本。 在我正在进行的测试中,我不太关心数据结构的内容。我只想要合理的默认值

此数据结构的一部分是递归树。更具体地说,一个类包含另一个类的集合,该集合包含它自己的子类列表。 类似于:

public class A
{
   private IEnumerable<B> bNodes;
   public A(IEnumerable<B> bNodes)
   {
      this.bNodes = bNodes;
   }
}

public class B
{
   private IEnumerable<B> children;
   public B(IEnumerable<B> children)
   {
      this.children = children;
   }
}


创建一个包含空Bs列表的

创建一个具有空Bs列表的实例很容易:

var fixture = new Fixture();
fixture.Inject(Enumerable.Empty<B>());

var a = fixture.Create<A>();
请注意
Create
方法的实现已更改,以及
handleRecursiverRequest
IEnumerable
的具体处理

为了使它在
Fixture
实例中可用,我还添加了这个
DepthRecursionBehavior

public class DepthRecursionBehavior : ISpecimenBuilderTransformation
{
    public ISpecimenBuilder Transform(ISpecimenBuilder builder)
    {
        return new DepthRecursionGuard(builder);
    }
}
这使我能够创建一棵小树:

var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
    .ToList().ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthRecursionBehavior());

var a = fixture.Create<A>();
var fixture=newfixture();
fixture.Behaviors.OfType()的
.ToList().ForEach(b=>fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(新的DepthRecursionBehavior());
var a=夹具。创建以使其在将来更容易



更新2013.11.13:从AutoFixture 3.13.0开始,递归深度可以通过该API进行配置。

有趣的是fixture.Inject(Enumerable.Empty())可以工作,但在我的真实代码中执行相同的操作会使DictionaryFiller失败,并导致“已添加具有相同键的项”。我不太清楚如何控制递归深度,你能提供一个例子吗…和往常一样,当你第一次发现它的时候非常简单。。。fixture.Behaviors.Remove(新ThrowingRecursionBehavior());fixture.Behaviors.Add(新的省略递归行为(1))//1的递归看起来是正确的,尽管我会使用
fixture.Behaviors.OfType().ToList().ForEach(b=>fixture.Behaviors.remove(b))删除现有的行为…DepthRecursionBehavior不存在。你是说省略递归行为吗?
public class DepthRecursionGuard : ISpecimenBuilderNode
{
    private readonly ISpecimenBuilder builder;
    private readonly Stack<object> monitoredRequests;

    public DepthRecursionGuard(ISpecimenBuilder builder)
    {
        if (builder == null)
        {
            throw new ArgumentNullException("builder");
        }

        this.monitoredRequests = new Stack<object>();
        this.builder = builder;
    }

    public object Create(object request, ISpecimenContext context)
    {
        if (this.monitoredRequests.Count(request.Equals) > 1)
            return this.HandleRecursiveRequest(request);

        this.monitoredRequests.Push(request);
        var specimen = this.builder.Create(request, context);
        this.monitoredRequests.Pop();
        return specimen;
    }

    private object HandleRecursiveRequest(object request)
    {
        if (typeof(IEnumerable<B>).Equals(request))
            return Enumerable.Empty<B>();

        throw new InvalidOperationException("boo hiss!");
    }

    public ISpecimenBuilderNode Compose(IEnumerable<ISpecimenBuilder> builders)
    {
        var builder = ComposeIfMultiple(builders);
        return new DepthRecursionGuard(builder);
    }

    public virtual IEnumerator<ISpecimenBuilder> GetEnumerator()
    {
        yield return this.builder;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    private static ISpecimenBuilder ComposeIfMultiple(
        IEnumerable<ISpecimenBuilder> builders)
    {
        var isSingle = builders.Take(2).Count() == 1;
        if (isSingle)
            return builders.Single();

        return new CompositeSpecimenBuilder(builders);
    }
}
public class DepthRecursionBehavior : ISpecimenBuilderTransformation
{
    public ISpecimenBuilder Transform(ISpecimenBuilder builder)
    {
        return new DepthRecursionGuard(builder);
    }
}
var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
    .ToList().ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthRecursionBehavior());

var a = fixture.Create<A>();