考虑以下表示家庭成员的方式:
public abstract class Human { }
public abstract class Child : Human
{
public ICollection<Parent> Parents { get; set; }
}
public abstract class Parent : Human
{
public ICollection<Child> Children { get; set; }
}
public class Son : Child { }
public class Daughter : Child { }
public class Mum : Parent { }
public class Dad : Parent { }
现在,我希望AutoFixture
生成一个Parent
,在Mum
和Dad
之间随机选择,并在Son
和Daughter
之间随机选择Parent
。我也希望它省略递归,所以如果它来自Child
并生成Parent
,它可以省略回到var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior());
var random = new Random();
fixture.Register<Parent>(() =>
{
switch (random.Next(1, 2))
{
case 1:
return fixture.Create<Mum>();
case 2:
return fixture.Create<Dad>();
default:
throw new NotImplementedException();
}
});
fixture.Register<Child>(() =>
{
switch (random.Next(1, 2))
{
case 1:
return fixture.Create<Son>();
case 2:
return fixture.Create<Daughter>();
default:
throw new NotImplementedException();
}
});
fixture.Create<Parent>();
的链接。
我尝试了以下自定义:
InvalidCastException
但它会抛出一个Parent -> Child -> Parent
(见下文)。
有没有办法配置AutoFixture以便它考虑Unhandled Exception: AutoFixture.ObjectCreationExceptionWithPath: AutoFixture was unable to
create an instance from AutoFixtureAbstractTrees.Parent because creation unexpectedly
failed with exception. Please refer to the inner exception to investigate the root cause of
the failure.
Request path:
AutoFixtureAbstractTrees.Mum
System.Collections.Generic.ICollection`1[AutoFixtureAbstractTrees.Child] Children
System.Collections.Generic.ICollection`1[AutoFixtureAbstractTrees.Child]
System.Collections.Generic.List`1[AutoFixtureAbstractTrees.Child]
System.Collections.Generic.IEnumerable`1[AutoFixtureAbstractTrees.Child] collection
System.Collections.Generic.IEnumerable`1[AutoFixtureAbstractTrees.Child]
AutoFixtureAbstractTrees.Child
AutoFixtureAbstractTrees.Son
System.Collections.Generic.ICollection`1[AutoFixtureAbstractTrees.Parent] Parents
System.Collections.Generic.ICollection`1[AutoFixtureAbstractTrees.Parent]
System.Collections.Generic.List`1[AutoFixtureAbstractTrees.Parent]
System.Collections.Generic.IEnumerable`1[AutoFixtureAbstractTrees.Parent] collection
System.Collections.Generic.IEnumerable`1[AutoFixtureAbstractTrees.Parent]
AutoFixtureAbstractTrees.Parent
Inner exception messages:
System.InvalidCastException: Unable to cast object of type
'AutoFixture.Kernel.OmitSpecimen' to type 'AutoFixtureAbstractTrees.Mum'.
递归,即使它实际上为每个实例随机选择了一个合适的子类?
catch
答案 0 :(得分:1)
您遇到此问题的原因是因为AutoFixture中存在设计缺陷。当你使用ISpecimenBuilder
扩展方法时,你基本上启动了一个新的解决方案上下文,而递归防护机制并没有抓住它。
看起来,在这种情况下,您可以使用Resolve
中的context
和Create
来解决问题,而不是使用[Fact]
public void WorkAround()
{
var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(3));
var random = new Random();
fixture.Customizations.Add(new ParentBuilder(random));
fixture.Customizations.Add(new ChildBuilder(random));
var actual = fixture.Create<Parent>();
Assert.True(0 < actual.Children.Count);
}
扩展方法:< / p>
ParentBuilder
此测试通过,并使用自定义类ChildBuilder
和public class ParentBuilder : ISpecimenBuilder
{
private readonly Random random;
public ParentBuilder(Random random)
{
this.random = random;
}
public object Create(object request, ISpecimenContext context)
{
var t = request as Type;
if (t == null || t != typeof(Parent))
return new NoSpecimen();
if (this.random.Next(0, 2) == 0)
return context.Resolve(typeof(Mum));
else
return context.Resolve(typeof(Dad));
}
}
public class ChildBuilder : ISpecimenBuilder
{
private readonly Random random;
public ChildBuilder(Random random)
{
this.random = random;
}
public object Create(object request, ISpecimenContext context)
{
var t = request as Type;
if (t == null || t != typeof(Child))
return new NoSpecimen();
if (this.random.Next(0, 2) == 0)
return context.Resolve(typeof(Son));
else
return context.Resolve(typeof(Daughter));
}
}
:
require
所有这一切,作为you've previously discovered,你在这里推动了AutoFixture的限制。它并非真正用于处理复杂的递归对象设计,如此处所示。