如何使用AutoFixture在保留类型自定义的同时使用自定义特性进行构建
本文关键字:自定义 构建 AutoFixture 何使用 保留 类型 | 更新日期: 2023-09-27 17:59:27
我正在尝试使用自动固定来创建对象,但有些属性我希望始终是默认的(而其他属性可以自动生成)。但是,每当我设置自定义项时,当我使用自定义项构建时,它就会被覆盖。
void Main()
{
var fixture = new Fixture();
fixture.Customize<Person>(composer => composer.With(p => p.Name, "Ben"));
var person = fixture.Build<Person>()
.With(p => p.DateOfBirth, new DateTime(1900, 1, 1))
.Create();
/* RESULT OF person below
Name null
DateOfBirth 1/1/1900
StreetAddress StreetAddressafd6b86b-376a-4355-9a9c-fbae34731453
State State019e867b-ac5e-418f-805b-a64146bc06bc
*/
}
public class Person
{
public string Name { get; set;}
public DateTime DateOfBirth { get; set;}
public string StreetAddress { get; set;}
public string State { get; set;}
}
Name
和DateOfBirth
属性自定义不冲突,所以我不知道为什么Name最终为null。我希望名字是Ben
。
如何获得它以便应用两个自定义项(即Name = "Ben"
和DateOfBirth = 1/1/1900
)?
正如@DavidOsborne正确指出的,您看到的行为是按设计的。
更好的方法是将您的自定义组织在单独的类中,然后根据特定测试场景的需要启用它们。
自定义对象实现ICustomization
接口,其工作是以特定方式配置Fixture
对象。这里有一个例子:
public class AllPersonsAreNamedBen : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<Person>(composer =>
composer.With(p => p.Name, "Ben"));
}
}
public class AllPersonsAreBornIn1900 : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<Person>(composer =>
composer.With(p => p.DateOfBirth, new DateTime(1900, 1, 1)));
}
}
您可以使用Customize
方法在特定的Fixture
上启用自定义,例如:
fixture.Customize(new AllPersonsAreNamedBen());
或:
fixture.Customize(new AllPersonsAreBornIn1900());
您还可以使用CompositeCustomization
类将多个自定义项组合为一个新的自定义项:
public class AllPersonsAreNamedBenAndAreBornIn1900 : CompositeCustomization
{
public AllPersonsAreNamedBenAndAreBornIn1900()
: base(new AllPersonsAreNamedBen(),
new AllPersonsAreBornIn1900())
{
}
}
这时你可以简单地说:
fixture.Customize(new AllPersonsAreNamedBenAndAreBornIn1900());
然而,请记住,在Fixture
上应用自定义的顺序很重要:正如@MarkSeemann在评论中指出的那样,最后一个获胜,并且可能覆盖前一个。这也是设计出来的。
因此,虽然可以组合适用于不同类型的现有自定义,但在这种特殊情况下,由于两个自定义都针对同一类型,因此必须创建一个新的自定义来封装组合的Person
类型的所有设置:
public class AllPersonsAreNamedBenAndAreBornIn1900 : CompositeCustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<Person>(composer =>
composer.With(p => p.Name, "Ben")
.With(p => p.DateOfBirth, new DateTime(1900, 1, 1)));
}
}
一般来说,保持您的自定义较小且以为中心使您能够在不同的测试中重用它们,并将它们组合用于特定的测试场景。
这看起来像是设计的:
请注意,构建方法链最好理解为一次性定制。它绕过
Fixture
实例上的所有自定义设置。相反,它允许在构建特定样本时进行细粒度控制。然而,在大多数情况下,添加基于约定的ICustomization
是一个更好、更灵活的选项。
来自CCD_ 15方法的文档。
我很感激这可能不是一个理想的答案。然而,文档确实提供了一个提示,说明您可能会如何获得一个。