使用自动固定将子实例上的属性值设置为固定值

本文关键字:属性 设置 实例 | 更新日期: 2023-09-27 18:36:44

在使用 Autofixture 构建父实例时,是否可以为子实例上的属性分配固定值?它将像超级按钮一样将默认值添加到子实例上的所有属性,但我想覆盖子实例上的某个属性并将其分配给特定值。

给定此父/子关系:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    public string Street { get; set; }
    public int Number { get; set; }
    public string City { get; set; }
    public string PostalCode { get; set; }
}

我想为地址实例上的 City 属性分配一个特定值。我在思考这个测试代码的行:

var fixture = new Fixture();
var expectedCity = "foo";
var person = fixture
    .Build<Person>()
    .With(x => x.Address.City, expectedCity)
    .Create();
Assert.AreEqual(expectedCity, person.Address.City);

这是不可能的。我想,通过反射例外

System.Reflection.TargetException : Object does not match target type.

。该自动固定装置尝试将值分配给 Person 实例上的 City 属性,而不是地址实例。

有什么建议吗?

是的,我知道我可以添加一个额外的步骤,如下所示:

var fixture = new Fixture();
var expectedCity = "foo";
// extra step begin
var address = fixture
    .Build<Address>()
    .With(x => x.City, expectedCity)
    .Create();
// extra step end
var person = fixture
    .Build<Person>()
    .With(x => x.Address, address)
    .Create();
Assert.AreEqual(expectedCity, person.Address.City);

。但希望第一个版本或类似的东西(更少的步骤,更简洁)。

注意:我正在使用自动夹具v3.22.0

使用自动固定将子实例上的属性值设置为固定值

为了完整起见,这里有另一种方法:

fixture.Customize<Address>(c => 
    c.With(addr => addr.City, "foo"));
var person = fixture.Create<Person>();

这将自定义创建所有Address实例

如果您最终经常使用它,则可能值得将其包装在ICustomization中:

public class AddressConventions : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<Address>(c => 
            c.With(addr => addr.City, "foo"));
    }
}
fixture.Customize(new AddressConventions());

不要对这个问题不屑一顾,但最简单的解决方案实际上可能是这样的:

[Fact]
public void SimplestThingThatCouldPossiblyWork()
{
    var fixture = new Fixture();
    var expectedCity = "foo";
    var person = fixture.Create<Person>();
    person.Address.City = expectedCity;
    Assert.Equal(expectedCity, person.Address.City);
}

属性分配显式值是大多数语言已经擅长的事情(C#当然可以),所以我认为AutoFixture不需要复杂的DSL来重现该功能的一半。

您可以在构建器上使用 Do 方法:

var person = this.fixture
               .Build<Person>()
               .Do( x => x.Address.City = expectedCity )
               .Create();

您还可以将实例注入并冻结到夹具中:

this.fixture.Inject( expectedCity );