如何单元测试简单属性有验证器设置?

lir*_*006 6 c# unit-testing fluentvalidation

我对多个模型对象中的某些属性有类似的规则,我想用自定义属性验证器替换它们,以避免单元测试中的代码重复.

我有我的财产验证人:

public class IntIdPropertyValidator: PropertyValidator
{
    public IntIdPropertyValidator()
        : base("Property {PropertyName} should be greater than 0")
    {
    }

    protected override bool IsValid(PropertyValidatorContext context)
    {
        var value = (int)context.PropertyValue;

        return value > 0;
    }
}
Run Code Online (Sandbox Code Playgroud)

并在模型验证器类中连接它:

public class SomeRequestValidator : AbstractValidator<CreateWordRequest>
{
    public SomeRequestValidator()
    {
        RuleFor(x => x.Id).SetValidator(new IntIdPropertyValidator());
    }
}
Run Code Online (Sandbox Code Playgroud)

试图测试:

[Test]
public void Validate_IdHasValidator_Success()
{
    Init();

    validator.ShouldHaveChildValidator(x => x.Id, typeof(IntIdPropertyValidator));
}
Run Code Online (Sandbox Code Playgroud)

但测试总是失败.

那么,我如何测试实际为属性Id设置的验证器?

Old*_*Fox 7

你使用ShouldHaveChildValidator的方式不对.Id是一个简单的类型.

ShouldHaveChildValidator正在复杂类型中使用.(另见源代码)

测试属性的正确方法是传递有效对象和无效对象,然后使用ShouldNotHaveValidationErrorForShouldHaveValidationErrorFor进行变换:

[Test]
public void Should_have_error_when_Id_Is_Ilegal() {
      validator.ShouldHaveValidationErrorFor(p => p.Id, new CreateWordRequest());
}

[Test]
public void Should_not_have_error_when_Id_Is_Legal() {
      validator.ShouldNotHaveValidationErrorFor(p => p.Id, new CreateWordRequest()
                                                           {
                                                                Id = 7
                                                           });
}
Run Code Online (Sandbox Code Playgroud)

编辑

以下代码将执行您要查找的验证:

[Test]
public void Validate_IdHasValidator_Success()
{
    var validator = new SomeRequestValidator();

    var descriptor = validator.CreateDescriptor();
    var matchingValidators = descriptor.GetValidatorsForMember(
                Extensions.GetMember<CreateWordRequest, int>(x => x.Id).Name);

    Assert.That(matchingValidators.FirstOrDefault(), Is.InstanceOf<IntIdPropertyValidator>());

}
Run Code Online (Sandbox Code Playgroud)

我想解释一下你不应该使用上述代码的原因.

当您使用UT类时,您将验证类行为是否不会受到损害.

创建自定义验证程序时,您将创建一个负责验证特定模型( - >业务规则)的类...

Id是一种简单类型,根据其父模型具有业务规则.因此,您需要Id通过模型验证器验证业务规则.

让我们假设你的一个模型突然需要改变.在这种情况下,您没有任何验证任何现有业务规则不会受到损害(或者您决定在内部进行更改IntIdPropertyValidator,这样的移动会影响任何地方,即使您不想这样做).

创建自定义Property Validator非常适合代码维护,但是测试应该针对模型验证器.

在复杂类型上,故事完全不同:

通常,复杂类型有自己的业务规则.在这种情况下,您必须为它们创建自定义验证器,然后验证父验证器使用正确的验证器.要验证的另一件事是:如果复杂类型是Null复杂的规则,例如"当属性值为X然后复杂类型状态为Y"时......