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

本文关键字:属性 AutoFixture 创建 复杂 组件 | 更新日期: 2023-09-27 18:07:50

我正在使用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,但没有设法解决它的方式。

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

AutoFixture是基于一组关于它可能被要求使用的API的规则和假设。假设它是在不了解ChildParent类或给定API中的任何其他类型的情况下创建和编译的。它只需要使用公共API。

把AutoFixture想象成一个非常迟钝的程序员,甚至不懂你的语言(甚至不懂英语)。你的API越简单,使用AutoFixture就越容易。

像这里描述的父/子关系这样的循环引用的问题是它破坏了封装。您需要创建至少一个初始状态为无效的类实例。很难让AutoFixture与这样的API一起工作,这主要是一个警告信号,表明API可能会从重构中受益。 此外,. net框架设计指南建议不要将数组公开为属性——尤其是可写属性。因此,有了更好的封装设计,对于AutoFixture、您自己和您的同事来说,API可能会更容易使用。

考虑到上面的API,我看不出有任何方法可以使它更容易使用。考虑一下如何删除循环引用并使集合属性为只读,这会容易得多。

为了记录,我已经很多年没有写过一个循环引用的API了,所以很有可能避免那些父/子关系。