【问题标题】:How to unit test simple property has validator set?如何对设置了验证器的简单属性进行单元测试?
【发布时间】:2015-06-27 14:33:50
【问题描述】:

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

我有我的属性验证器:

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;
    }
}

并将其连接到模型验证器类中:

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

试图测试:

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

    validator.ShouldHaveChildValidator(x => x.Id, typeof(IntIdPropertyValidator));
}

但测试总是失败。

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

【问题讨论】:

    标签: c# unit-testing fluentvalidation


    【解决方案1】:

    您以错误的方式使用ShouldHaveChildValidatorId 是一个简单的类型。

    ShouldHaveChildValidator 用于复杂类型。 (另见source code

    测试属性的正确方法是传递有效对象和无效对象,然后使用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
                                                               });
    }
    

    编辑

    以下代码将执行您正在寻找的验证:

    [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>());
    
    }
    

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

    当您进行 UT 课程时,您确认课程行为不会受到损害。

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

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

    假设您的某个模型突然需要更改。在这种情况下,您没有任何验证可以证明您现有的任何业务规则都不会受到损害(或者您决定在 IntIdPropertyValidator 内部进行更改,即使您不想这样做,这样的举动也会影响任何地方)。

    创建自定义 Property Validator 非常有利于代码维护,但是,测试应该针对模型验证器。

    在复杂类型上,情况完全不同:

    通常复杂类型有自己的业务规则。在这种情况下,您必须为它们创建一个自定义验证器,然后验证父验证器是否使用正确的验证器。另外要验证的是:如果复杂类型是Null或者复杂的规则比如“当属性值为X,那么复杂类型的状态是Y”...

    【讨论】:

    • 嗯,是的,我知道,这就是我自己测试自定义验证器的方式。但关键是,现在我不想对每个具有该验证器的道具的模型类都这样做。我想测试是否真的为道具设置了验证器,而不是测试它是否工作正常,因为这就是自定义验证器的测试所做的。
    • @liri2006 我更新了我的答案,用一种方法来进行您正在寻找的验证......我还解释了为什么你不应该这样做......
    • 这非常有帮助!代码和解释。
    猜你喜欢
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 2017-09-11
    • 1970-01-01
    • 2019-12-05
    • 1970-01-01
    • 2010-12-25
    • 1970-01-01
    相关资源
    最近更新 更多