在@Evelio 的回答的基础上,我将提供一个关于如何对自定义验证器进行单元测试的答案,因为这似乎在互联网上的任何地方都没有阐明,这是搜索时出现的热门话题之一怎么做。
@Evelio 的答案非常接近,但它可以做更多的解释。
要测试您的验证,您需要有一个将验证属性附加到其成员数据的类。在这里,我使用了一个新的自定义验证器,它对我的名为 FeeTimeUnitValidator 的项目有意义。这个验证器接受一个范围和另一个属性作为输入。如果其他属性为零,则验证器附加到的属性无关紧要。但如果其他属性不为零,则该属性需要在范围内。
这是我用于测试的 MockClass:
class MockClass
{
public decimal Fee { get; set; }
[FeeTimeUnitValidator(otherPropertyName:"Fee", minValue:1, maxValue:12)]
public int attributeUnderTest { get; set; }
public int badOtherProperty { get; set; }
[FeeTimeUnitValidator(otherPropertyName: "badOtherProperty", minValue: 1, maxValue: 12)]
public int badAttributeUnderTest { get; set; }
[FeeTimeUnitValidator(otherPropertyName: "NotFoundAttribute", minValue: 1, maxValue: 12)]
public int nameNotFoundAttribute { get; set; }
}
注意属性验证:
[FeeTimeUnitValidator(otherPropertyName:"Fee", minValue:1, maxValue:12)]
这表示检查属性“费用”作为费用属性(即,它必须是非零),然后范围是 1 - 12。
我在单元测试类中实例化类并使用 setup 方法设置它。由于该类上有三个属性具有验证器,因此我将属性名称传递给安装程序类。
private MockClass classUnderTest;
private ValidationContext context;
FeeTimeUnitValidator setup(string attributeUnderTest)
{
classUnderTest = new MockClass();
classUnderTest.Fee = 0;
var propertyInfo = typeof(MockClass).GetProperty(attributeUnderTest);
var validatorArray = propertyInfo.GetCustomAttributes(typeof(FeeTimeUnitValidator), true);
Assert.AreEqual(1, validatorArray.Length);
var validator = validatorArray[0];
Assert.IsTrue(validator.GetType().Equals(typeof(FeeTimeUnitValidator)));
context = new ValidationContext(classUnderTest, null, null);
return (FeeTimeUnitValidator)validator;
}
有一些有趣的事情。我正在使用@Evelio 的方法从属性中提取验证器。这是在设置例程的第 3 行和第 4 行中完成的。然后,由于这是一个单元测试方法,我做了一些断言来确保我得到了我所期望的。当我将此模式转移到另一个验证器的另一个单元测试类时,这实际上遇到了一个问题。
然后另一个关键是我创建了 ValidationContext(因为更复杂的验证器需要一个上下文来查找它们引用的其他属性——在我的例子中,我使用它来查找 Fee 属性)。当我研究如何对这些自定义验证器进行单元测试时,让我绊倒的是 ValidationContext。我找不到有关如何创建它们的任何信息。我相信属性验证的“上下文”是属性所在的类。这就是为什么我使用类实例作为第一个参数来创建验证上下文。然后,这为验证器提供了对类上其他属性的访问权限,因此您可以进行跨属性验证。
现在我已经创建了上下文和指向验证器的指针,我可以跳入单元测试本身以确保验证器正常工作:
[TestMethod]
public void TestInRangeIsValidWhenFeeNonZero()
{
// Arrange
var validator = setup("attributeUnderTest");
classUnderTest.Fee = 10;
// Act
ValidationResult value12 = validator.GetValidationResult(12, context);
ValidationResult value1 = validator.GetValidationResult(1, context);
ValidationResult value5 = validator.GetValidationResult(5, context);
// Assert
Assert.AreEqual(ValidationResult.Success, value12);
Assert.AreEqual(ValidationResult.Success, value1);
Assert.AreEqual(ValidationResult.Success, value5);
}
如果我的验证器不需要上下文(即,它可以验证属性而不参考其他属性),那么我可以使用更简单的 IsValid() 接口,但如果验证器需要非空上下文,您必须像我在这里所做的那样使用 GetValidationResult() 方法。
我希望这可以帮助其他可能正在编写验证器并且像我一样对单元测试充满虔诚的人。 :)
Here is a good article on creating custom validators.