大廈@ 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)]
這是說,以檢查屬性「費」的收費性質(即,它必須是無-zero),然後範圍是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()的更簡單的接口,但是如果驗證器需要非null上下文,則必須使用GetValidationResult()像我在這裏完成的方法。
我希望這可以幫助別人誰可能會寫驗證器,並像我一樣對宗教單元測試。 :)
Here is a good article on creating custom validators.
這個解決方案的問題在於它測試你在該屬性上的所有驗證器,而不僅僅是正則表達式,所以你沒有很好地隔離你的測試用例。你有沒有考慮將Regex存儲在全局可訪問的地方,無論是在資源文件還是在Web配置?由於您只是想在此時驗證您的正則表達式,因此您可以使用Regex.Match()單獨測試該模式。 – joelmdev 2013-09-24 13:46:25
由於你只是想驗證一個屬性,你可能想考慮['Validator.TryValidateProperty'](https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validator。 validateproperty%28v = vs.110%29.aspx)方法。這是假設你的Person類實際上不僅僅是一個電話號碼。 – Erik 2016-03-18 12:48:34
好東西兄弟,謝謝! – 2018-01-23 17:08:07