在AutoFixture中创建复杂子对象时使用父属性的值

8
我正在使用AutoFixture为涉及父对象和复杂子对象的结构生成数据,就像这样:

public class Parent
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Child[] Children { get; set; }
}

public class Child
{
    public string Name { get; set; }
    public int ParentId { get; set; }
}

有没有一种方法可以自动将生成的Child对象的属性ParentId设置为分配给父对象的id?目前我的解决方案看起来像这样,不太美观:
var parent = fixture.Build<Parent>().Without(p => p.Children).CreateAnonymous();
parent.Children = fixture.CreateMany<Child>(10).ToArray();

foreach (var i in parent.Children)
{
    i.ParentId = parent.Id;
}

感觉好像有一种更好的方法可以解决这个问题,但是我可能还没有想到?我尝试了创建一个自定义的ISpecimenBuilder,但是也没有成功解决它。

1个回答

6
AutoFixture基于一组规则和对其可能使用的API的假设。请考虑它是在没有任何关于ChildParent类或给定API中的其他类型的先前知识的情况下创建和编译的。它所能使用的仅仅是公共API。
将AutoFixture视为一个非常晦涩的程序员,他甚至不懂你的语言(甚至不是英语)。您可以使您的API更加 fool-proof,这样使用AutoFixture就会更容易。
像这里描述的父/子关系这样的循环引用的问题在于它破坏了封装性。您需要最初以无效状态创建至少一个类实例。难以使AutoFixture与这种API配合工作,主要应当被视为警示标志,表明该API可能受益于重构。
此外,.NET Framework设计准则建议不要将数组公开为属性 - 特别是可写属性。因此,通过更好的封装设计,该API可能会更容易使用,无论是对于AutoFixture还是您自己及同事。

考虑到以上API,我并没有看到有任何方法可以使其更易于使用。请考虑如何消除循环引用并使集合属性只读,这样会更容易。

值得一提的是,多年来我都没有编写具有循环引用的API,因此完全可以避免父/子关系。


谢谢你的回复,马克!我完全同意你对API设计的看法。不幸的是,在这种情况下,我无法影响API的设计,我只能使用它。尽管我们的API不方便,但我可能仍然会继续使用AutoFixture,因为它可以让事情变得更容易。 - Niklas Söderberg
1
如果您总是像示例中那样创建“Parent”实例,您可以使用“Customize”方法封装该行为... - Mark Seemann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接