Question

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.

Était-ce utile?

La solution

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 */);
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top