hokkos
hokkos

Reputation: 499

How to automatically set the parent object in a child property with autofixture

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.

Upvotes: 3

Views: 1363

Answers (1)

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174329

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)));

Upvotes: 3

Related Questions