【问题标题】:AutoFixture - Creation of "Valid" and "Invalid" instances and [AutoData]AutoFixture - 创建“有效”和“无效”实例和 [AutoData]
【发布时间】:2021-02-20 15:15:35
【问题描述】:

我创建了以下示例模型:

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?

【问题讨论】:

    标签: c# testing autofixture nunit-3.0


    【解决方案1】:

    是的,您可以,但是您的设置代码的复杂性将取决于您的域的复杂性。

    您可以声明一个自定义,使用有效数据构建您的 DTO 模型,然后通过自定义 [AutoData] 属性使用它,并在测试内部使用 .Customize<T>().Build<T>() 自定义一些带有无效数据的 DTO。

    现在,如果您想从测试参数中提供无效的 DTO,您可以尝试实现 [Invalid] 属性,该属性将自定义各个测试参数,然后使用 [Frozen] 在其他生成的模型中使用该值。

    对于[Invalid] 属性,您可以实现AutoFixture.NUnit3 包中的CustomizeAttributeAutoFixture 中的IParameterCustomizationSource

    您将看到自定义属性的输出是 ICustomization,这意味着在属性内部您可能会有一个字典,根据参数类型输出无效实体的自定义。

    注意:我真的建议您使用第一种方法,因为它可以清楚地表明输入数据的无效方式,并且更容易断言结果。

    【讨论】:

    • 感谢您详尽而详细的解释。最初我希望根据第二个示例来实现我的解决方案,但你是对的,在第一个情况下,它会以何种方式被测试的实例是无效的。
    【解决方案2】:

    我可能会将 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);
    

    这可能是一个很好的样板,可以用接口和泛型重构为更花哨的东西。有时“过早的优化是万恶之源”

    【讨论】:

      猜你喜欢
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-29
      • 1970-01-01
      相关资源
      最近更新 更多