Fluent TestValidate 不会为使用 SetValidator 在 List 上设置的规则引发验证错误

Fluent TestValidate not raising validation errors for rules set on List with SetValidator

在使用 Fluent 的测试助手 TestValidate 方法对我的规则进行单元测试时,当对象列表为空时抛出 TestValidationException。验证器设置指定 NotNull 规则。

验证器如下所示

public class RequestValidator : AbstractValidator<Request>
{
    public RulebookRequestValidator()
    {
        RuleFor(x => x.Id).NotEmpty();
        RuleFor(x => x.Name).NotEmpty();
        RuleForEach(x => x.EntryRequests).SetValidator(new EntryRequestValidator()).NotNull(); // Would like to validate this rule when EntryRequests is null.
    }
}

子验证器看起来像这样,

public class EntryRequestValidator : AbstractValidator<EntryRequest>
{
        public EntryRequestValidator()
        {
            RuleFor(x => x.EntryRequestId).NotEmpty();
            RuleForEach(x => x.Messages).NotNull().SetValidator(new MessagesValidator());
        }
 }

在我的单元测试中

[TestMethod]
public void Should_Have_Error_When_Object_Is_Empty()
{
    // arrange
    Request model = new () { EntryRequests = new () };
    var validator = new RequestValidator();

    // assert
    var result = validator.TestValidate(model);

    // act
    Assert.IsFalse(result.IsValid);
    result.ShouldHaveValidationErrorFor(x => x.Id)
            .WithErrorCode(NotEmptyValidatorErrorCode);
    result.ShouldHaveValidationErrorFor(x => x.Name)
            .WithErrorCode(NotEmptyValidatorErrorCode);
    result.ShouldHaveValidationErrorFor(x => x.EntryRequests); // throws ValidateTestException. 
 }

这是在单元测试列表中测试子验证器的正确方法吗?寻找使用 TestValidate 对该规则进行单元测试的方法。

您的验证器工作正常,但有一个小问题。

我们来看看这条规则:

RuleForEach(x => x.EntryRequests).SetValidator(new EntryRequestValidator()).NotNull();

它基本上说:运行 对 EntryRequest collection.

中的每个元素进行 NotNull 检查(并执行 EntryRequestValidator)

它不起作用,因为你的 collection 是 : EntryRequests = new ()。它没有元素,所以没有什么要验证的。

改为:

RuleFor(x => x.EntryRequests).NotEmpty(); // throws validation error when collection is null or empty
RuleForEach(x => x.EntryRequests).SetValidator(new EntryRequestValidator()).NotNull(); 

使用上述规则,您将在以下情况下收到验证错误:

  • EntryRequests = null
  • EntryRequests = 空列表
  • 此列表的任何元素为空

加上来自嵌套验证器的所有验证

public class RulebookRequestValidator : AbstractValidator<Request>
{
    public RulebookRequestValidator()
    {
        RuleFor(x => x.Id).NotEmpty();
        RuleFor(x => x.Name).NotEmpty();
        RuleFor(x => x.EntryRequests).NotNull()
            .ForEach(element => element.SetValidator(new EntryRequestValidator()).NotNull());
    }
}

您需要检查对象是否为 null,然后为集合元素设置验证器。

为了提高可读性,您可以定义自定义规则生成器扩展方法。

public static IRuleBuilderOptions<T, IEnumerable<TK>> MustBeValidCollection<T, TK>(
        this IRuleBuilder<T, IEnumerable<TK>> ruleBuilder,
        AbstractValidator<TK> validator)
    {
        return ruleBuilder.NotNull()
            .ForEach(collection => collection.NotNull().SetValidator(validator));
    }

并像 RuleFor(x => x.EntryRequests).MustBeValidCollection(new EntryRequestValidator());

一样使用它