如何对自定义验证属性进行单元测试

Mig*_*tom 41 c# validation unit-testing asp.net-mvc-2

我有一个自定义的asp.net mvc类验证属性.我的问题是如何对其进行单元测试?测试类具有属性是一回事,但这实际上不会测试其中的逻辑.这是我想测试的.

[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; }
Run Code Online (Sandbox Code Playgroud)

.....为简洁而删除}

[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;

    }
}
Run Code Online (Sandbox Code Playgroud)

我试着按如下方式编写测试,但这不起作用:

[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);
}
Run Code Online (Sandbox Code Playgroud)

ModelStateDictionary不包含这个自定义属性的关键.它仅包含标准验证属性的属性.

为什么是这样?

测试这些自定义属性的最佳方法是什么?

Ale*_*sky 49

您的属性EligabilityStudentDebtsAttribute只是一个标准类,就像其他一切一样,只需对IsValid()方法进行单元测试.如果它工作正常,请相信Framework该属性正常工作.

所以:

[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)
}
Run Code Online (Sandbox Code Playgroud)

  • 这是进行跨属性验证的最佳方法吗?(涉及多个属性的模型验证) (2认同)
  • 记得在单元测试程序集中添加对`System.ComponentModel.DataAnnotations`的引用,否则你看不到`IsValid`方法(它也不会编译但是我花了一些时间来发现它) (2认同)

Pet*_*esz 18

您的自定义验证属性可能取决于其他属性的状态.在这种情况下,您可以使用System.ComponentModel.DataAnnotations.Validator静态方法,例如:

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

  • 您可能想添加true标志来验证所有属性-“ Validator.TryValidateObject(model,context,results,true);” -使用NUnit测试我的验证时遇到问题,除非我提供的“ validateAllProperties”为true,否则“受保护的重写ValidationResult IsValid(..)”中的验证未命中-因此测试未按预期运行,因此我无法调试到我的代码。 (2认同)

Ily*_*dik 13

我发现它IsValid不适用于字符串等简单类型。例如,如果您对不是对象的字符串查询参数进行验证。此外,直接在属性上测试值更容易,而无需提供整个对象。它还允许检查错误消息。它是这样工作的:

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

var isSuccess = result == ValidationResult.Success;
var errorMessage = result?.ErrorMessage;
Run Code Online (Sandbox Code Playgroud)

此代码仅测试输入值的验证,而不测试其他内容。

PS我已经在 dotnet core 中对此进行了测试,但我认为这也适用于普通的 dotnet。