12

I'm having a bit of trouble getting my head around testing my custom validation attribute. As the method signature is protected when I invoke the IsValid method in my unit test, I can't pass in a Mock<ValidationContext> object, it's calling the base virtual bool IsValid(object value) instead.

ValidationAttribute

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
    var otherPropertyInfo = validationContext.ObjectType.GetProperty(this.otherPropertyName);
    var otherPropertyValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);

    if (value != null)
    {
        if (otherPropertyValue == null)
        {
            return new ValidationResult(FormatErrorMessage(this.ErrorMessage));
        }
    }

    return ValidationResult.Success;
}

Test

[Test]
public void Should_BeValid_WhenPropertyIsNullAndOtherPropertyIsNull()
{
    var attribute = new OptionalIfAttribute("test");
    var result = attribute.IsValid(null);

    Assert.That(result, Is.True);
}

If I'm unable to pass in a mocked validation context, then how can I test this class properly?

ediblecode
  • 11,701
  • 19
  • 68
  • 116

1 Answers1

16

You can use the Validator class to perform the validation manually without having to mock anything. There is a brief article on it here. I would probably do something like

[Test]
public void Should_BeValid_WhenPropertyIsNullAndOtherPropertyIsNull()
{
    var target = new ValidationTarget();
    var context = new ValidationContext(target);
    var results = new List<ValidationResult>();

    var isValid = Validator.TryValidateObject(target, context, results, true);

    Assert.That(isValid, Is.True);
}

private class ValidationTarget
{
    public string X { get; set; }

    [OptionalIf(nameof(X))]
    public string OptionalIfX { get; set; }
}

You could optionally make assertions on results.

Matt Cole
  • 2,491
  • 17
  • 21
  • This is what I in fact ended up doing, but forgot to put the answer here. – ediblecode Jan 24 '16 at 23:28
  • 4
    You should set the validateAllProperties arg in Validator.TryValidateObject, or else it does not check the properies, var isValid = Validator.TryValidateObject(target, context, results, true); – Feiyu Zhou Jun 27 '17 at 16:15
  • 1
    Thanks @FeiyuZhou, without validateAllProperties = true it does not validate my custom attribute and return IsValid = true every time. – maximelian1986 Sep 28 '18 at 07:39