How can I unit test my custom validation attribute

C#ValidationUnit Testingasp.net Mvc-2

C# Problem Overview


I have a custom asp.net mvc class validation attribute. My question is how can I unit test it? It would be one thing to test that the class has the attribute but this would not actually test that the logic inside it. This is what I want to test.

[Serializable]
[EligabilityStudentDebtsAttribute(ErrorMessage = "You must answer yes or no to all questions")]
public class Eligability
{
    [BooleanRequiredToBeTrue(ErrorMessage = "You must agree to the statements listed")]
    public bool StatementAgree { get; set; }

    [Required(ErrorMessage = "Please choose an option")]
    public bool? Income { get; set; }

.....removed for brevity }

[AttributeUsage(AttributeTargets.Class)]
public class EligabilityStudentDebtsAttribute : ValidationAttribute
{
    // If AnyDebts is true then 
    // StudentDebts must be true or false

    public override bool IsValid(object value)
    {
        Eligability elig = (Eligability)value;
        bool ok = true;
        if (elig.AnyDebts == true)
        {
            if (elig.StudentDebts == null)
            {
                ok = false;
            }
        }
        return ok;

    }
}

I have tried to write a test as follows but this does not work:

[TestMethod]
public void Eligability_model_StudentDebts_is_required_if_AnyDebts_is_true()
{

   // Arrange
   var eligability = new Eligability();
   var controller = new ApplicationController();

   // Act
   controller.ModelState.Clear();
   controller.ValidateModel(eligability);
   var actionResult = controller.Section2(eligability,null,string.Empty);

   // Assert
   Assert.IsInstanceOfType(actionResult, typeof(ViewResult));
   Assert.AreEqual(string.Empty, ((ViewResult)actionResult).ViewName);
   Assert.AreEqual(eligability, ((ViewResult)actionResult).ViewData.Model);
   Assert.IsFalse(((ViewResult)actionResult).ViewData.ModelState.IsValid);
}

The ModelStateDictionary does not contain the key for this custom attribute. It only contains the attributes for the standard validation attributes.

Why is this?

What is the best way to test these custom attributes?

C# Solutions


Solution 1 - C#

Your attribute EligabilityStudentDebtsAttribute is just a standard class, like everything else, just unit test the IsValid() method. If it works OK, trust to Framework that attribute works OK.

So:

[Test]
public void AttibuteTest()
{
   // arrange
   var value = //.. value to test - new Eligability() ;
   var attrib = new EligabilityStudentDebtsAttribute();

   // act
   var result = attrib.IsValid(value);

   // assert
   Assert.That(result, Is.True)
}

Solution 2 - C#

Your custom validation attribute might be dependent on the state of other properties. In this case you can use the System.ComponentModel.DataAnnotations.Validator static methods, for example:

var model = ...
var context = new ValidationContext(model);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(model, context, results, true);
Assert.True(isValid);

Solution 3 - C#

I have found out that IsValid does not work well on simple types like string. E.g. if you have a validation on a string query parameter that is not an object. Additionally it's easier to test a value directly on the attribute without having to provide a whole object. It also allows to check the error message. This is how it works:

string input = "myteststring";
var myAttribute = new MyAttribute()
var result = attribute.GetValidationResult(input, new ValidationContext(input));

var isSuccess = result == ValidationResult.Success;
var errorMessage = result?.ErrorMessage;

This code tests only the validation of your input value and nothing else.

P.S. I have tested this in dotnet core, but I would think this works for ordinary dotnet as well.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMightyAtomView Question on Stackoverflow
Solution 1 - C#Alexander BeletskyView Answer on Stackoverflow
Solution 2 - C#Peter RieszView Answer on Stackoverflow
Solution 3 - C#Ilya ChernomordikView Answer on Stackoverflow