2016-07-31 70 views
4

我想使用自动混合来创建一个对象,但他们是某些属性,我想总是默认(而其余的可以自动生成)。但是,每当我设置自定义时,它会在我使用自定义创建时被覆盖。如何使用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。我希望名字是“本”。 ?

我怎样才能得到它这样既定制应用(即名称=“奔”和出生日期= 1/1/1900

回答

6

正如@DavidOsborne正确指出的那样,您看到的行为是as designed

A 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))); 
    } 
} 

您可以通过使用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事项应用顺序:最后1个胜场,并有可能覆盖的正如@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

“AllPersonsAreNamedBen”是否将[重写](http://blog.ploeh.dk/2012/07/31/TheorderofAutoFixtureCustomizationsmatter)'AllPersonsAreBornIn1900'? –

+0

我站好了。由于这两个定制工作在相同的类型,他们绝对会。感谢您的呼唤!这是AutoFixture的一个方面,时不时地咬我 - 我希望我可以像增量那样组合多个自定义,所以*坏*,我有时会忘记它是不可能的。 –

+0

我更新了我的答案以纠正错误。 –

6

这看起来像它的设计:

注意构建方法链最好理解为一次性定制,它绕过Fixture实例上的所有定制,而是在构建特定样本时允许进行细粒度控制,但在大多数情况下,添加基于约定的ICustomization更好,更灵活的选择。

...来自Build()方法的文档。

我明白这可能不是一个理想的答案。但是,文档确实提供了有关如何到达其中的提示。

相关问题