【问题标题】:Unit testing FluentValidation rules for classes with sub/child classes对具有子/子类的类的单元测试 FluentValidation 规则
【发布时间】:2012-12-17 13:50:29
【问题描述】:

当我们正在验证的对象具有也在被验证的子类时,是否可以为 fluentvalidation 类编写单元测试。

例如: 我的课是这样的

public class TestModel
{

    public class SubData
    {
        public int SubDataVal { get; set; }
    }

    public int ParentVal { get; set; }
    public SubData Sub { get; set; }

}

我的验证逻辑如下所示:

public class TestModelValidator : AbstractValidator<TestModel>
{
    public TestModelValidator()
    {
        RuleFor(o => o.ParentVal).GreaterThan(0);
        RuleFor(o => o.Sub.SubDataVal).GreaterThan(0);
    }
}

当我写下面的单元测试时

    [Test]
    public void Should_have_error_when_val_is_zero()
    {
        validator = new TestModelValidator();
        validator.ShouldHaveValidationErrorFor(model => model.ParentVal, 0);
    }

我收到“System.NullReferenceException:对象引用未设置为对象的实例”。例外 FluentValidation.TestHelper.ValidatorTester`2.ValidateError(T instanceToValidate)

(如果我删除 RuleFor(o => o.Sub.SubDataVal).GreaterThan(0); 行,那么它可以工作!)

同样,如果我尝试对实际的子类进行单元测试:

    [Test]
    public void Should_have_error_when_sub_dataVal_is_zero()
    {
        validator = new TestModelValidator();
        validator.ShouldHaveValidationErrorFor(model => model.Sub.SubDataVal, 0);
    }

我收到“System.Reflection.TargetException:对象与目标类型不匹配”。来自 FluentValidation.TestHelper.ValidatorTester`2.ValidateError(T instanceToValidate)

【问题讨论】:

    标签: c# unit-testing fluentvalidation


    【解决方案1】:

    您可以对模型和子模型进行单元测试,但您需要更改验证类以使用单独的验证器类来验证子模型:

    public class TestModelValidator : AbstractValidator<TestModel>
    {
        public TestModelValidator()
        {
            RuleFor(o => o.ParentVal).GreaterThan(0);
            RuleFor(o => o.Sub).SetValidator(new SubDataValidator());
        }
    }
    
    public class SubDataValidator : AbstractValidator<SubData>
    {
        public SubDataValidator()
        {
            RuleFor(o => o.SubDataVal).GreaterThan(0);
        }
    }
    

    然后您可以编写单元测试来测试每个验证器或同时测试两者。

    【讨论】:

    • 这是真的,并且允许“ShouldHaveValidationErrorFor”方法工作。就我个人而言,我更喜欢以不同的方式编写单元测试,这样我就不必为了使单元测试工作而更改核心代码。
    • 这并不是为了让代码可测试而改变实现——这就是 Fluent 的用途,因此存在“SetValidator”方法
    • 我的意思是我们没有遵循 TDD。我们已经有一个复杂的对象,并且它已经被一个流利的验证器验证,我不想更改现有的工作代码,以便我的单元测试能够通过。
    【解决方案2】:

    我得出的结论是,对于这个 ShouldHaveValidationErrorFor 只是无法处理子类,所以不得不手动进行。即

        [Test]
        public void Should_have_error_when_val_is_zero()
        {
            validator = new TestModelValidator();
            TestModel testRequest = new TestModel();
            //populate with dummy data
            var result = validator.Validate(testRequest);
            Assert.That(result.Errors.Any(o => o.PropertyName== "ParentVal"));
        }
    

    【讨论】:

      【解决方案3】:

      使用 MSTest 和 FluentAssertions,您可以编写

      [TestMethod]
      public void Should_have_error_when_val_is_zero()
      {
          // Given
          var validator = new TestModelValidator();
          var testModel = TestModel
          {
              ParentVal = 0
          }; // You should create a invalid TestModel object here
      
          // When
          validator.Validate(testModel).IsValid.Should().BeFalse();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-08
        • 2011-03-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多