首页 > 解决方案 > 测试 FluentValidation ChildRules

问题描述

给定以下对象:

public class PatchDTO
{
    public PatchDTO()
    {
        Data = new List<Datum>();
    }
    public List<Datum> Data { get; set; }

    public class Datum
    {
        public Datum()
        {
            Attributes = new Dictionary<string, object>();
        }
        public string Id { get; set; }
        public Dictionary<string, object> Attributes { get; set; }
    }
}

我的验证器设置如下:

RuleFor(oo => oo.Data)
    .NotEmpty()
    .WithMessage("One or more Data blocks must be provided");

RuleForEach(d => d.Data).ChildRules(datum =>
{
    datum.RuleFor(d => d.Id)
        .NotEmpty()
        .WithMessage("Invalid 'Data.Id' value");
});

我正在尝试使用测试扩展进行测试:

[Theory]
[InlineData(null)]
[InlineData("")]
public void Id_Failure(string id)
{
    dto.Data[0].Id = id;
    var result = validator.TestValidate(dto);
    result.ShouldHaveValidationErrorFor(oo => oo.Data[0].Id)
        .WithErrorMessage("Invalid 'Data.Id' value");
}

但是当我运行测试时它说:

FluentValidation.TestHelper.ValidationTestException
  HResult=0x80131500
  Message=Expected a validation error for property Id
----
Properties with Validation Errors:
[0]: Data[0].Id

但正如您在“验证错误”下看到的那样,它实际上已在验证失败中出现,但并未将其与此测试联系起来。那么我如何测试这些 ChildRules 或告诉测试扩展方法它实际上应该检查哪个属性?

(我也validator.ShouldHaveValidationErrorFor直接使用了同样的结果)

标签: c#.net-corefluentvalidation

解决方案


我以前遇到过这个问题,并求助于使用字符串重载ShouldHaveValidationErrorFor

以下(nunit)测试通过

[TestCase(null)]
[TestCase("")]
public void Id_InvalidValue_HasError(string id)
{
    var fixture = new Fixture();
    var datum = fixture.Build<PatchDTO.Datum>().With(x => x.Id, id).Create();
    var dto = fixture.Build<PatchDTO>().With(x => x.Data, new List<PatchDTO.Datum> { datum }).Create();

    var validator = new PatchDTOValidator();

    var validationResult = validator.TestValidate(dto);

    validationResult.ShouldHaveValidationErrorFor("Data[0].Id")
        .WithErrorMessage("Invalid 'Data.Id' value");
}

自从我查看它已经有一段时间了,但我认为问题在于ShouldHaveValidationErrorFor属性名称的扩展匹配,并且属性表达式重载不会将属性名称解析为“Data[0].Id”。如果您检查验证结果,您将得到一个ValidationError看起来像这样的对象

{
   "PropertyName":"Data[0].Id",
   "ErrorMessage":"Invalid 'Data.Id' value",
   "AttemptedValue":"",
   "CustomState":null,
   "Severity":0,
   "ErrorCode":"NotEmptyValidator",
   "FormattedMessageArguments":[

   ],
   "FormattedMessagePlaceholderValues":{
      "PropertyName":"Id",
      "PropertyValue":""
   },
   "ResourceName":null
}

编辑:

快速查看属性表达式重载,如下所示

public IEnumerable<ValidationFailure> ShouldHaveValidationErrorFor<TProperty>(Expression<Func<T, TProperty>> memberAccessor)
{
  return ValidationTestExtension.ShouldHaveValidationError(this.Errors, ValidatorOptions.PropertyNameResolver(typeof (T), memberAccessor.GetMember<T, TProperty>(), (LambdaExpression) memberAccessor), true);
}

大概您可以使用另一个/编写您自己的属性名称解析器来处理这种情况,因为它是可设置的。您可能必须深入研究表达式才能做到这一点。


推荐阅读