使用 Autofixture 将子实例的属性值设置为固定值
Setting property value on child instance to a fixed value with Autofixture
在使用 Autofixture 构建父实例时,是否可以为子实例的属性分配固定值?它将像魅力一样为子实例上的所有属性添加默认值,但我想覆盖并为子实例上的一个属性分配一个特定值。
鉴于此 parent/child 关系:
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.
...Autofixture 尝试将值分配给 Person 实例而不是 Address 实例上的 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);
...但希望有第一个版本或类似的东西(更少的步骤,更简洁)。
注意:我使用的是 Autofixture v3.22.0
您可以在构建器上使用 Do 方法:
var person = this.fixture
.Build<Person>()
.Do( x => x.Address.City = expectedCity )
.Create();
您还可以将您的实例注入并冻结到夹具中:
this.fixture.Inject( expectedCity );
不要对这个问题不屑一顾,但最简单的解决方案实际上可能是这样的:
[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);
}
大多数语言已经 excel 为属性分配显式值(C# 确实如此),所以我认为 AutoFixture 不需要复杂的 DSL 来重现该功能的一半。
为了完整起见,这里有另一种方法:
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());
在使用 Autofixture 构建父实例时,是否可以为子实例的属性分配固定值?它将像魅力一样为子实例上的所有属性添加默认值,但我想覆盖并为子实例上的一个属性分配一个特定值。
鉴于此 parent/child 关系:
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.
...Autofixture 尝试将值分配给 Person 实例而不是 Address 实例上的 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);
...但希望有第一个版本或类似的东西(更少的步骤,更简洁)。
注意:我使用的是 Autofixture v3.22.0
您可以在构建器上使用 Do 方法:
var person = this.fixture
.Build<Person>()
.Do( x => x.Address.City = expectedCity )
.Create();
您还可以将您的实例注入并冻结到夹具中:
this.fixture.Inject( expectedCity );
不要对这个问题不屑一顾,但最简单的解决方案实际上可能是这样的:
[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);
}
大多数语言已经 excel 为属性分配显式值(C# 确实如此),所以我认为 AutoFixture 不需要复杂的 DSL 来重现该功能的一半。
为了完整起见,这里有另一种方法:
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());