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.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
System.Linq.Enumerable.WhereSelectArrayIterator2.MoveNext() at
System.Collections.Generic.List
1..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.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.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.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.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.WhereSelectArrayIterator
2.MoveNext() at
System.Collections.Generic.List1..ctor(IEnumerable
1 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.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.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