问题描述
我创建了以下示例模型:
internal sealed class Bike : IVehicle
{
public Bike(
Engine engineType,WindowHue windowHue,Vehicle transport,ushort wheelsCount,string name) =>
(EngineType,WindowHue,Transport,WheelsCount,Name) =
(engineType,windowHue,transport,wheelsCount,name);
public WindowHue WindowHue { get; }
public Engine EngineType { get; }
public Vehicle Transport { get; }
public ushort WheelsCount { get; }
public string Name { get; }
}
我目前正在为 Bike 验证器编写单元测试,我想使用 AutoFixture 创建 Bike 类的实例,这些实例具有被认为有效和无效的值。有没有办法指示 AutoFixture 如何创建这些类型的实例并告诉它根据正在运行的单元测试获取有效或无效的实例?例如:在检查 Bike 类的有效实例是否通过验证的测试用例中,我希望 AutoFixture 创建一个有效的 Bike 实例。 我试图通过创建自定义样本构建器来实现这种行为,但似乎注册的最后一个用于创建请求类型的实际实例。另一个想法是创建构建器类,该类将使用 AutoFixture 创建有效和无效实例 [通过“创建”方法] 并在测试用例中使用它,但我认为这不是一个好主意,因为它会导致创建冗余代码 [每个测试模型的构建器类]。 如果上述行为是可能的,那么有没有办法通过使用 [AutoData] 属性来创建这样的实例,这样我就不必在测试用例正文中调用 AutoFixture?
解决方法
可以,但是设置代码的复杂程度取决于域的复杂程度。
您可以声明将使用有效数据构建 DTO 模型的自定义,然后通过自定义 [AutoData]
属性使用它,并在测试内部使用 .Customize<T>()
或使用无效数据自定义一些 DTO 或.Build<T>()
。
现在,如果您想从测试参数中提供无效的 DTO,您可以尝试实现一个 [Invalid]
属性,该属性将自定义单个测试参数,然后使用 [Frozen]
使用其他生成的值模型。
对于 [Invalid]
属性,您可以实现 CustomizeAttribute
包中的 AutoFixture.NUnit3
或 IParameterCustomizationSource
中的 AutoFixture
。
正如您将看到的,自定义属性的输出是一个 ICustomization
,意思是在属性内部,您可能有一个字典,根据参数类型输出对无效实体的自定义。
注意:我真的建议您使用第一种方法,因为它使输入数据无效的方式一目了然,并使断言结果更容易。
,我可能会忽略 automapper 并创建一个类来负责创建测试所需的不同类型(无效或有效)的对象:
枚举.cs
public enum BikeType
{
Valid,Invalid
}
BikeCreator.cs
public static class BikeCreator
{
private Bike CreateValidBike()
{
return new Bike() //make this object "valid"
}
private Bike CreateInvalidBike()
{
return new Bike(); //make this object "invalid"
}
public Bike CreateInstance(BikeType bikeType)
{
Bike bike = null;
switch (bikeType)
{
case BikeType.Valid:
user = CreateValidBike();
break;
case BikeType.Invalid:
user = CreateInvalidBike();
break;
};
return bike;
}
}
这允许我以下列方式调用该类:
//arrange
var invalidBike = BikeCreator.CreateInstance(BikeType.Invalid);
var validBike = BikeCreator.CreateInstance(BikeType.Valid);
这可能是一个很好的样板,可以用接口和泛型重构为更花哨的东西。有时“过早优化是万恶之源”