我一直在将 Fluent Validations 从 10 更新到 11,但突然出现了很多单元测试错误,这让我相信 Fluent Validations 并未执行所有规则。这似乎违背了所有文档,而且我没有发现其他人对此抱怨,所以我很困惑。
我有一个测试,查找多个空值,并且应该为每个空值返回一个失败,但是它只返回第一个失败,交换规则顺序会使错误返回不同。
如有任何提示,我们将不胜感激。
public sealed class Validator : AbstractValidator<Command>
{
public Validator()
{
//ClassLevelCascadeMode = CascadeMode.Continue;
RuleFor(x => x.Id).ValidateId();
RuleFor(x => x.Name).ValidateAccountName();
RuleFor(x => x.Description).ValidateAccountDescription();
RuleFor(x => x.Status).ValidateAccountStatus();
When(
x => !(x.prop1is null) || !(x.prop2 is null) || !(x.prop 3 is null),
() =>
{
RuleFor(x => x.prop1Enum).NotNull().IsInEnum();
RuleFor(x => x.prop2Number).ValidateNumber();
RuleFor(x => x.prop3Number).ValidateNumber();
}
);
}
}
测试
public void Validator_ShouldReturnErrors_WhenAccountInfoIsPartiallyProvided(
bool excludeProp1,
bool excludeProp2,
bool excludeProp3,
UpdateAccount.Validator sut,
IFixture fixture
)
{
// arrange
var command = BuildValidCommand(fixture, excludeProp1, excludeProp2, excludeprop3)
.Create();
// act
var result = sut.Validate(command);
// assert
using var _ = new AssertionScope();
result.Errors.Should().HaveCountLessOrEqualTo(3);
if (excludeprop1)
{
result.Errors.Should()
.Contain(
f => f.PropertyName == nameof(UpdateAccount.Command.prop1) &&
f.ErrorMessage.Contains("must not be empty")
);
}
if (excludeProp2)
{
result.Errors.Should()
.Contain(
f => f.PropertyName == nameof(UpdateAccount.Command.Prop2) &&
f.ErrorMessage.Contains("must not be empty")
);
}
if (excludeProp3)
{
result.Errors.Should()
.Contain(
f => f.PropertyName == nameof(UpdateAccount.Command.Prop3) &&
f.ErrorMessage.Contains("must not be empty")
);
}
}
我发现我的测试的数据生成器使验证器处于这种糟糕的状态。我已经通过将它们置于正确的状态来修复它们。
我在升级到 FluentValidation 11 时也有过相同的经历,但原因不同。我将其包含在这里也许可以帮助其他人寻找这个问题。
我的测试代码使用 AutoFixture 来实例化验证器类。 这似乎无害:
var fixture = new Fixture();
// Omitted code that configures dependencies
var sut = fixture.Create<MyValidator>();
var model = new MyModel();
var result = sut.TestValidate(model);
result.ShouldHaveValidationErrorFor(m => m.SecondProperty);
但是,由于升级到 FluentValidation 版本 11 和默认的 AutoFixture 配置,它会自动将验证器上的公共属性设置为选定的值。实际上,正在执行的代码类似于:
var sut = new MyValidator(/* dependencies */)
{
RuleLevelCascadeMode = CascadeMode.Stop,
ClassLevelCascadeMode = CascadeMode.Stop
};
就我而言,问题可以通过使用来解决:
fixture.OmitAutoProperties = true;