我正在尝试使用autofixture来创建一个对象,但它们是我想要始终默认的某些属性(其余的可以自动生成)。但是,每当我设置自定义时,它都会在我使用自定义构建时被覆盖。
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?
答案 0 :(得分:12)
正如@DavidOsborne正确指出的那样,您所看到的行为是as designed。
better approach是将您的自定义组织在单独的类中,然后根据特定测试方案的需要启用它们。
自定义对象实现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)));
}
}
您可以使用Fixture
方法在特定Customize
上启用自定义,例如:
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指出的那样在评论中。这也是by design。
因此,虽然可以组合使用不同类型的现有自定义项,但在这种特殊情况下,由于两个自定义项都定位于同一类型,因此您将拥有创建新的自定义以封装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)));
}
}
作为一般规则,保持自定义较小且集中使您能够在不同的测试中reuse them,将它们组合到特定的测试场景中。
答案 1 :(得分:9)
这看起来像是设计:
请注意,Build方法链最好被理解为一次性Customization。它绕过
Fixture
实例上的所有自定义项。相反,它可以在构建特定样本时进行细粒度控制。但是,在大多数情况下,添加基于约定的ICustomization
是更好,更灵活的选项。
...来自Build()
方法的文档。
我很欣赏这可能不是一个理想的答案。但是,文档确实提供了如何到达一个文档的提示。
答案 2 :(得分:0)
如已接受的答案所述,自定义会相互覆盖,因此您必须为要使用的每种属性组合编写一个自定义。
我写了一个库,允许您编写自定义项,这样它们就不会彼此覆盖,而是会合并在一起。这样一来,您可以对People named Ben
进行一个自定义,而对Born in 1900
进行一个自定义,然后可以将它们与Compose函数一起进行组合。
它并没有完全解决最初的问题,但是可能会给您一些有关如何实现所需目标的想法。通过创建可处理自定义内容的自定义IFixture实现来完成Compose功能。
https://github.com/LethargicDeveloper/Lift.AutoFixture
编辑:我看到“ 4个月前处于活动状态”。我错过了“ 3年”。很抱歉复活了这么旧的帖子,但希望这会有用。