Autofixture ObjectCreationException - circular reference: RuntimeParameterInfo or Ploeh.AutoFixture.Kernel.SeededRequest

StackOverflow https://stackoverflow.com/questions/21245921

Question

I've been trying to model some simple immutable objects, in which I have two constructor overloads: one which accepts an argument for each of the readonly properties, and one which accepts an instance of itself for cloning (for ease of use when most property values will be the same as another instance's).

public class Parent {
    public Parent(Child child, Pet pet) {
        Child = child;
        Pet = pet;
    }

    public Parent(Parent template) {
        Child = template.Child;
        Pet = template.Pet;
    }

    public Child Child { get; private set; }
    public Pet Pet { get; private set; }
}

This test passes, as I would expect:

[Theory]
[AutoData]
public void Properties_Equal_Constructor_Arguments(Child expectedChild, Pet expectedPet)
{
    // act
    var sut = new Parent(expectedChild, expectedPet);

    // assert
    sut.Child.Should().Be(expectedChild);
    sut.Pet.Should().Be(expectedPet);
}

But this test throws a Ploeh.AutoFixture.ObjectCreationException, unable to create an instance of type System.Reflection.RuntimeParameterInfo (using AutoData parameter), or type Ploeh.AutoFixture.Kernel.SeededRequest (without using AutoData) (?!?)

[Theory]
[AutoData]
public void Properties_Equal_Properties_Of_Template_Constructor_Argument(Parent template)
{
    // arrange
    //var fixture = new Fixture();            // yields same error but for type
    //var template = fixture.Create<Parent>();// Ploeh.AutoFixture.Kernel.SeededRequest
    var expectedChild = template.Child;
    var expectedPet = template.Pet;

    // act
    var sut = new Parent(template);

    // assert
    sut.Child.Should().Be(expectedChild);
    sut.Pet.Should().Be(expectedPet);
}

First of all, I don't spot any circular reference in my classes, like you usually see in questions about this where the child object has a property reference to its parent (like happens with database entity modeling sometimes). Second, when I have received this error in the past, it was referring to a circular reference on a type plainly used in my class, unlike in this case.

Why is this happening?

For completeness, here are the other relevant classes and the full error message received:

public class Child {
    public Child(string value) {
        Value = value;
    }
    public string Value { get; private set; }
}

public class Pet {
    public Pet(string name) {
        Name = name;
    }
    public string Name { get; private set; }
}

System.InvalidOperationException An exception was thrown while getting data for theory AutoFixtureTests.CircularReferenceTests.Properties_Equal_Properties_Of_Template_Constructor_Argument: Ploeh.AutoFixture.ObjectCreationException: AutoFixture was unable to create an instance of type System.Reflection.RuntimeParameterInfo because the traversed object graph contains a circular reference. Information about the circular path follows below. This is the correct behavior when a Fixture is equipped with a ThrowingRecursionBehavior, which is the default. This ensures that you are being made aware of circular references in your code. Your first reaction should be to redesign your API in order to get rid of all circular references. However, if this is not possible (most likely because parts or all of the API is delivered by a third party), you can replace this default behavior with a different behavior: on the Fixture instance, remove the ThrowingRecursionBehavior from Fixture.Behaviors, and instead add an instance of OmitOnRecursionBehavior. Path: AutoFixtureTests.Parent template --> AutoFixtureTests.Parent --> AutoFixtureTests.Parent template --> Ploeh.AutoFixture.Kernel.SeededRequest

at Ploeh.AutoFixture.Kernel.ThrowingRecursionHandler.HandleRecursiveRequest(Object request, IEnumerable1 recordedRequests) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at System.Linq.Enumerable.WhereSelectArrayIterator2.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable
1 source) at Ploeh.AutoFixture.Kernel.MethodInvoker.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Xunit.AutoDataAttribute.GetData(MethodInfo methodUnderTest, Type[] parameterTypes) at Xunit.Extensions.TheoryAttribute.d_7.MoveNext() at Xunit.Extensions.TheoryAttribute.EnumerateTestCommands(IMethodInfo method) at Xunit.Extensions.TheoryAttribute.<>c_DisplayClass5.b__1() at Xunit.Extensions.TheoryAttribute.LambdaTestCommand.Execute(Object testClass)

and when not using AutoDataAttribute:

Ploeh.AutoFixture.ObjectCreationException AutoFixture was unable to create an instance of type Ploeh.AutoFixture.Kernel.SeededRequest because the traversed object graph contains a circular reference. Information about the circular path follows below. This is the correct behavior when a Fixture is equipped with a ThrowingRecursionBehavior, which is the default. This ensures that you are being made aware of circular references in your code. Your first reaction should be to redesign your API in order to get rid of all circular references. However, if this is not possible (most likely because parts or all of the API is delivered by a third party), you can replace this default behavior with a different behavior: on the Fixture instance, remove the ThrowingRecursionBehavior from Fixture.Behaviors, and instead add an instance of OmitOnRecursionBehavior. Path: AutoFixtureTests.Parent template --> AutoFixtureTests.Parent --> AutoFixtureTests.Parent at Ploeh.AutoFixture.Kernel.ThrowingRecursionHandler.HandleRecursiveRequest(Object request, IEnumerable1 recordedRequests) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at System.Linq.Enumerable.WhereSelectArrayIterator2.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection)
at System.Linq.Enumerable.ToList(IEnumerable1 source) at Ploeh.AutoFixture.Kernel.MethodInvoker.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TracingBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.TerminatingWithPathSpecimenBuilder.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context) at Ploeh.AutoFixture.SpecimenFactory.Create(ISpecimenContext context, T seed) at Ploeh.AutoFixture.SpecimenFactory.Create(ISpecimenContext context) at AutoFixtureTests.CircularReferenceTests.Properties_Equal_Properties_Of_Template_Constructor_Argument() in AutoFixtureTests.cs: line 28

No correct solution

OTHER TIPS

For anyone trying to avoid a circular reference as a result of Entity Framework and virtual members, here is a customization to ignore them when generating mock data.

public class IgnoreVirtualMembers : ISpecimenBuilder
{
    public Type ReflectedType { get; }

    public object Create(object request, ISpecimenContext context)
    {
        var pi = request as PropertyInfo;
        if (pi != null) //// is a property
        {
            if (this.ReflectedType == null || //// is hosted anywhere
                this.ReflectedType == pi.ReflectedType) //// is hosted in defined type
            {
                if (pi.GetGetMethod().IsVirtual)
                {
                    return new OmitSpecimen();
                }
            }
        }

        return new NoSpecimen();
    }
}

public class IgnoreVirtualMembersCustomisation : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(new IgnoreVirtualMembers());
    }
}

With the usage :

new Fixture().Customize(new IgnoreVirtualMembersCustomisation());
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top