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.
Validator.TryValidateObject only checks the RequiredAttribute
s (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 */);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With