I am bit familiar with ASP.Net MVC but weak in writing unit tests. I read an article about how to write unit test code when working with these classes and interface ValidationAttribute
and IClientValidatable
. Here is the link to the article:
http://www.codeproject.com/Articles/990538/Unit-Testing-Data-Validation-with-MVC
I was doing custom validation. The custom validation code as follows
public class DateValTest
{
[Display(Name = "Start Date")]
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? StartDate { get; set; }
[Display(Name = "End Date")]
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
[MyDate(ErrorMessage = "Back date entry not allowed")]
[DateGreaterThanAttribute(otherPropertyName = "StartDate", ErrorMessage = "End date must be greater than start date")]
public DateTime? EndDate { get; set; }
}
public class MyDateAttribute : ValidationAttribute, IClientValidatable
{
public DateTime _MinDate;
public MyDateAttribute()
{
_MinDate = DateTime.Today;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
DateTime _EndDat = DateTime.Parse(value.ToString(), CultureInfo.InvariantCulture);
DateTime _CurDate = DateTime.Today;
int cmp = _EndDat.CompareTo(_CurDate);
if (cmp > 0)
{
// date1 is greater means date1 is comes after date2
return ValidationResult.Success;
}
else if (cmp < 0)
{
// date2 is greater means date1 is comes after date1
return new ValidationResult(ErrorMessage);
}
else
{
// date1 is same as date2
return ValidationResult.Success;
}
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "restrictbackdates",
};
rule.ValidationParameters.Add("mindate", _MinDate);
yield return rule;
}
}
So, I tried to write unit test code for the above validation. Please look at my unit test code and tell me if I am going in the right direction because I do not know if I wrote it properly or miss something. please have a look.
[TestClass]
public class MyDateAttribute_Test
{
[TestMethod]
public void IsValid_Test()
{
var model = new MyDateAttribute { _MinDate = DateTime.Today.AddDays(-10) }; //set value
ExecuteValidation(model, "Back date entry not allowed");
}
private void ExecuteValidation(object model, string exceptionMessage)
{
try
{
var contex = new ValidationContext(model);
Validator.ValidateObject(model, contex);
}
catch (ValidationException exc)
{
Assert.AreEqual(exceptionMessage, exc.Message);
return;
}
}
}
Do I need to use Assert.AreEqual()
in try block too or should it be only in catch block?
There is no reason at all to be using a
try/catch
block in yourTestMethod
.Firstly your attribute is implementing
IClientValidatable
which means you want client side validation and you can only provide one message to theModelClientValidationRule
which in turn passes it the thejQuery.Validator
.The second part of article you linked to seems to be for testing cases where you might returns different error messages based on certain conditions which cannot apply when using client side validation, and in your case, you only have one error message anyway, so all you need to test is that an invalid model will return a
ValidationException
.Personally I cannot conceive of any reason to return different error messages based on different conditions in a
ValidationAtribute
, and the correct approach would be to create separate validation attributes. Even if you were to take that approach, all its testing is that one hard code string you have written matches another hard code string inside the attribute which is a pointless test anyway. The test would only be meaningful if you were to define properties (say)public string ErrorMessage1 { private set; get; }
andpublic string ErrorMessage1 { private set; get; }
and test that the appropriate exceptions' error message matched the values of one of those properties.Note that you can simplify your
IsValid()
method toThen to test that an invalid value will throw a
ValidationException
From a logical perspective, your test is fine. That is, if
Validator.ValidateObject(model, contex);
successfully validates the object, then it neither returns anything (as it's avoid
method) nor throws an exception. So logically there is nothing to assert here.However, depending on your unit test framework, you may need to assert something to tell the framework that your test indeed did execute and was successful (some frameworks return inconclusive if you do not have a positive assertion). So for completeness' sake I would make your method look like: