3

I want to use autofixture to create an object graph where children have a reference to the parent object. For example :

class A
{
  public List<B> Children { get; set; }
}

class B
{
  public A Parent { get; set; }
}

I tried to make a behavior that handles the recursion, but I don't know how to emit the parent object as the content of the property.

public class AutoParentOnRecursionBehavior : ISpecimenBuilderTransformation
{
    public ISpecimenBuilder Transform(ISpecimenBuilder builder)
    {
        if (builder == null)
            throw new ArgumentNullException("builder");

        return new RecursionGuard(builder, new AutoParentOnRecursionHandler());
    }
}

public class AutoParentOnRecursionHandler : IRecursionHandler
{
    public object HandleRecursiveRequest(
        object request,
        IEnumerable<object> recordedRequests)
    {
        object handleRecursiveRequest = recordedRequests.First(x => x.Equals(request));
        return ....
    }
}

Thanks.

Edit : I am thinking of a generic way, without having to specify the types A and B or even the property Children. For all properties of a property type that contains the object, set them to the parent object. In other words all properties of a type that trigger the recursion guard set them to the last object in the creation hierarchy.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
hokkos
  • 500
  • 6
  • 17
  • 2
    Related http://stackoverflow.com/questions/17087788/creating-recursive-tree-with-autofixture – Nikos Baxevanis Jun 25 '13 at 14:44
  • 2
    Would it be possible for you to change the API of your classes? The design proposed here is not only hard for AutoFixture to deal with, but will in general be a perpetual source of pain for you and your team members. – Mark Seemann Jun 26 '13 at 20:16

1 Answers1

2

My answer assumes that

  1. B.Parent should be null if you create B directly.
  2. B.Parent should be set to the instance of A that contains it, if you create A.

This can be achieved with the following rather simple customizations when using PostProcessorFor:

fixture.Customize<B>(c => c.Without(x => x.Parent));
fixture.PostProcessorFor<A>(a => { foreach(var b in a.Children) b.Parent = a; });

Some asserts to illustrate the result:

var b = fixture.Create<B>();
Assert.Null(b.Parent);

var a = fixture.Create<A>();
Assert.True(a.Children.All(b => ReferenceEquals(b.Parent, a)));
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Thanks for your answer, I could definitely use it but I was thinking of a more generic way, without having to specify the types A and B or even the property Children. For all properties of a property type that contains the object, set them to the parent object. In other words all properties of a type that trigger the recursion guard set them to the last object in the creation hierarchy. – hokkos Jun 25 '13 at 15:02
  • 1
    @hokkos: What about a property that triggers the recursion guard for a property of a type *other* than the last object in the hierarchy? `A.Children(of type B) -> B.Children(of type C) -> c.GrandFather(of type A)` – Daniel Hilgarth Jun 25 '13 at 15:06