考虑以下方式来代表家庭成员:
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
之间随机选择 child 的地方和 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
(见下文)。有没有办法配置 AutoFixture 以便它考虑
Parent -> Child -> Parent
递归,即使它实际上为每个实例随机选择了一个合适的子类?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'.
最佳答案
您遇到此问题的原因是 AutoFixture 中的设计缺陷。当您使用 Create
扩展方法,您本质上启动了一个新的解析上下文,而递归保护机制不会捕捉到它。
看起来,在这种情况下,您可以使用 ISpecimenBuilder
解决该问题。 s 和 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);
}
此测试通过,并使用自定义类
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));
}
}
综上所述,如 you've previously discovered ,您正在插入 AutoFixture 的极限。它并不是真正设计用于处理像这里显示的那样的复杂递归对象设计。
关于abstract-class - AutoFixture 可以省略类层次结构之间的递归吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48438939/