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());
一样使用它
在使用 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.
它不起作用,因为你的 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());