IValidatableObject passes validation but StringLength is Invalid
Asked Answered
E

1

9

I have a test class with a couple tests that check to see if the entity IsValid. I moved to using IValidatableObject from having my own custom validation but I'm stuck with the correct validation technique.

This is my Test class:

[TestFixture]
public class StudentTests {
    private static Student GetContactWithContactInfo()
    {
        return new Student(new TestableContactRepository())
                            {
                                Phone = "7275551111"
                            };
    }

    private static Student GetContactWithoutContactInfo()
    {
        return new Student(new TestableContactRepository());
    }

    [Test]
    public void Student_Saving_StudentHasInfo_IsValid ()
    {
        // Arrange
        Student student = GetContactWithContactInfo();
        // Act
        student.Save();
        // Assert
        Assert.IsTrue(student.IsValid);
    }

    [Test]
    public void Student_Saving_StudentDoesNotHaveInfo_IsNotValid ()
    {
        // Arrange
        Student student = GetContactWithoutContactInfo();
        // Act
        student.Save();
        // Assert
        Assert.IsFalse(student.IsValid);
    }
}

This is my entity:

public class Student : IValidatableObject
{
    private readonly IContactRepository contactRepository;

    public Student(IContactRepository _contactRepository)
    {
        contactRepository = _contactRepository;
        Contacts = new List<Student>();
    }

    [Required]
    public int Id { get; private set; }

    [StringLength(10, MinimumLength = 10)]
    public string Phone { get; set; }


    public List<Student> Contacts { get; private set; }

    public bool IsValid { get; private set; }

    public void Save()
    {
        if (IsValidForPersistance())
        {
            IsValid = true;
            Id = contactRepository.Save();
        }
    }

    private bool IsValidForPersistance()
    {
        return Validator.TryValidateObject(this, new ValidationContext(this), null, true);
    }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (string.IsNullOrEmpty(Phone) && Contacts.All(c => string.IsNullOrEmpty(c.Phone)))
            yield return new ValidationResult("The student or at least one contact must have a phone number entered", new[] { "Phone Number" });
    }
}

As you can see the tests test for IsValid by calling the IsValidForPersistance. Validate will eventually have more validation .

The above tests all pass using this method but this test below also passes but should not.

[Test]
public void Student_Saving_HasContactInfoWithInvalidLength_IsNotValid()
{
    // Arrange
    Contact student = GetContactWithoutContactInfo();
    student.Phone = "string";

    // Act
    student.Save();

    // Assert
    Assert.IsFalse(student.IsValid);
}

Here I'm setting my own Phone value of an invalid length string. I expect validation to fail because of the StringLength annotation set at min and max 10 characters.

Why is this passing?

Update There was a problem with the custom validation, updated the code with the change. Along with the suggestion from nemesv about not having a private modifier on the Phone property it now works. I've updated all the code to working.

Enyo answered 1/9, 2012 at 12:0 Comment(1)
I'm looking into this link right now as it has a demo project. The project implements some extra helper classes that work with the Validator. codeproject.com/Articles/256183/…Enyo
A
18

Validator.TryValidateObject only checks the RequiredAttributes (and also other things like type level attributes and IValidatableObject implementation) by default.

If you need to validate all the attributes like StringLength etc. you need to set the validateAllProperties parameter of the method to true

private bool IsValidForPersistance() {
    return Validator.TryValidateObject(this, 
                                       new ValidationContext(this), 
                                       null,
                                       true /* validateAllProperties */);
}
Arithmetic answered 1/9, 2012 at 17:7 Comment(2)
I've updated my code and have the validateAllProperties value set to true now but I still get the same result. That same test still passes as if it is validEnyo
You code works for me with validateAllProperties = true. Only one thing I've change in your Phone property public string Phone { private get; set; } I've made the get public so it should be public string Phone { get; set; }Arithmetic

© 2022 - 2024 — McMap. All rights reserved.