如何在保留类型自定义的同时使用AutoFixture构建自定义属性? [英] How to use AutoFixture to build with customized properties while keeping type customizations?
问题描述
我正在尝试使用自动固定装置创建对象,但是某些属性我希望始终默认设置(其余属性可以自动生成).但是,每当我设置自定义项时,使用自定义项进行构建时都会被覆盖.
I am trying to use autofixture to create an object but there are certain properties that I want to always be defaulted (while the rest could be auto generated). However, whenever I setup an customization it gets overwritten when I build with customizations.
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最终为空.我希望名称是 Ben
.
The Name
and DateOfBirth
property customizations do not conflict so I don't know why Name ends up being null. I would expect name to be Ben
.
如何获取它以便应用两种自定义设置(即 Name ="Ben"
和 DateOfBirth = 1/1/1900
)?
How can I get it so both customizations are applied (ie. Name = "Ben"
and DateOfBirth = 1/1/1900
)?
推荐答案
正如@DavidOsborne正确指出的那样,您看到的行为是
As @DavidOsborne correctly pointed out, the behavior you are seeing is as designed.
更好的方法是将您的自定义内容组织在单独的类中,然后根据特定测试场景的需要启用它们.
A better approach is to organize your customizations in separate classes and then enable them as needed by a specific test scenario.
定制对象实现 ICustomization
接口,其任务是以特定方式配置 Fixture
对象.这是一个示例:
A customization object implements the ICustomization
interface and its job is to configure the Fixture
object in a specific way. Here's an example:
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
上启用自定义,例如:
You can enable a customization on a specific Fixture
by using the Customize
method, for example:
fixture.Customize(new AllPersonsAreNamedBen());
或:
fixture.Customize(new AllPersonsAreBornIn1900());
您还可以使用 CompositeCustomization
类将多个自定义项组合成一个新的自定义项:
You can also combine multiple customizations into a new one by using the CompositeCustomization
class:
public class AllPersonsAreNamedBenAndAreBornIn1900 : CompositeCustomization
{
public AllPersonsAreNamedBenAndAreBornIn1900()
: base(new AllPersonsAreNamedBen(),
new AllPersonsAreBornIn1900())
{
}
}
这时您可以简单地说:
fixture.Customize(new AllPersonsAreNamedBenAndAreBornIn1900());
但是,请记住,对 Fixture
进行自定义的顺序很重要:最后一个获胜,并且可能覆盖,例如@MarkSeemann在评论中指出.这也是通过设计.
However, keep in mind that the order in which the customizations are applied on a Fixture
matters: the last one wins and can potentially override the previous ones, as @MarkSeemann pointed out in the comments. This, too, is by design.
因此,当您可以组合适用于不同类型的现有自定义项时,在这种情况下,由于两种自定义项均针对同一类型,因此您必须创建一个新的自定义项,用于封装组合的 Person
类型的所有设置:
So, while you can combine existing customizations that work on different types, in this particular case, since both customizations target the same type, you'll have to create a new customization to encapsulate all the settings for the Person
type combined:
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)));
}
}
As a general rule, keeping your customizations small and focused enables you to reuse them in different tests, combining them for specific test scenarios.
这篇关于如何在保留类型自定义的同时使用AutoFixture构建自定义属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!