Как вызвать атрибут проверки для тестирования?
Я использую функцию RegularExpressionAttribute из DataAnnotations для проверки и хочу проверить мое регулярное выражение. Есть ли способ вызвать атрибут непосредственно в unit test?
Я хотел бы сделать что-то похожее на это:
public class Person
{
[RegularExpression(@"^[0-9]{3}-[0-9]{3}-[0-9]{4}$")]
public string PhoneNumber { get; set; }
}
Затем в unit test:
[TestMethod]
public void PhoneNumberIsValid
{
var dude = new Person();
dude.PhoneNumber = "555-867-5309";
Assert.IsTrue(dude.IsValid);
}
Или даже
Assert.IsTrue(dude.PhoneNumber.IsValid);
Ответы
Ответ 1
В итоге я использовал статический класс Validator из пространства имен DataAnnotations. Мой тест теперь выглядит следующим образом:
[TestMethod]
public void PhoneNumberIsValid()
{
var dude = new Person();
dude.PhoneNumber = "666-978-6410";
var result = Validator.TryValidateObject(dude, new ValidationContext(dude, null, null), null, true);
Assert.IsTrue(result);
}
Ответ 2
Просто новый объект RegularExpressionAttribute.
var regularExpressionAttribute = new RegularExpressionAttribute("pattern");
Assert.IsTrue(regularExpressionAttribute.IsValid(objToTest));
Ответ 3
Прошу прощения за ответ.
Я здесь новый. Если вы хотите проверить каждый атрибут ValidationAttribute в изоляторе, вы можете перейти к следующему примеру, например:
[Test]
public void Test_the_State_value_IsRequired()
{
string value = "Finished";
var propertyInfo = typeof(TimeoffTemporalIncapacityEntry).GetProperty("State");
var attribute = propertyInfo.GetCustomAttributes(typeof(RequiredAttribute), true).Cast<RequiredAttribute>().FirstOrDefault();
Assert.IsTrue(attribute.IsValid(value));
}
Ответ 4
Я использовал предложение @Martin вместе со статическим константным файлом, который позволил мне не указывать строку регулярного выражения локально
[TestMethod]
public void Test_Regex_NationalinsuranceNumber()
{
var regularExpressionAttribute = new RegularExpressionAttribute(Constants.Regex_NationalInsuranceNumber_Validate);
List<string> validNINumbers = new List<string>() { "TN311258F", "QQ123456A" };
List<string> invalidNINumbers = new List<string>() { "cake", "1234", "TS184LZ" };
validNINumbers.ForEach(p => Assert.IsTrue(regularExpressionAttribute.IsValid(p)));
invalidNINumbers.ForEach(p => Assert.IsFalse(regularExpressionAttribute.IsValid(p)));
}
Ответ 5
Вы можете использовать этот класс для проверки любого типа ValidationAttribute в изоляции:
T = тип класса, содержащий свойство,
A = тип ValidationAttribute
Пример:
string stateValue = "Pendiente";
ValidationAttributeValidator<ConfirmationTemporalIncapacityEntry, RequiredAttribute> validator =
new ValidationAttributeValidator<ConfirmationTemporalIncapacityEntry, RequiredAttribute>();
Assert.IsTrue(validator.ValidateValidationAttribute("State", stateValue));
public class ValidationAttributeValidator<T,A>
{
public ValidationAttributeValidator() { }
public bool ValidateValidationAttribute(string property, object value)
{
var propertyInfo = typeof(T).GetProperty(property);
var validationAttributes = propertyInfo.GetCustomAttributes(true);
if (validationAttributes == null)
{
return false;
}
List<ValidationAttribute> validationAttributeList = new List<ValidationAttribute>();
foreach (object attribute in validationAttributes)
{
if (attribute.GetType() == typeof(A))
{
validationAttributeList.Add((ValidationAttribute)attribute);
}
}
return(validationAttributeList.Exists(x => x.IsValid(value)));
}
}
Ответ 6
Основываясь на ответе @Evelio, я собираюсь дать ответ на вопрос, как вы unit test настраиваемые валидаторы, поскольку это, похоже, не сочтено нигде в Интернете, и это один из лучших хитов, которые появляются при поиске как это сделать.
Ответ на @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)]
Это говорит, чтобы проверить свойство "Плата" как свойство Fee (т.е. оно должно быть ненулевым), а затем диапазон равен 1 - 12.
Я создаю класс класса unit test и настраиваю его с помощью метода установки. Поскольку в этом классе есть три атрибута, которые имеют валидатор, я передаю имя атрибута в класс установки.
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 процедуры установки. Затем, поскольку это метод unit test, я делаю некоторые утверждения, чтобы убедиться, что я получил то, что ожидал. Это действительно вызвало проблему, когда я перенес этот шаблон в другой класс unit test для другого валидатора.
Тогда другой ключ заключается в том, что я создаю ValidationContext (поскольку более сложные валидаторы нуждаются в контексте для поиска других атрибутов, к которым они относятся - в моем случае я использую его для поиска атрибута Fee). Когда я изучал, как unit test эти пользовательские валидаторы, то, что меня отключало, было ValidationContext. Я не мог найти никакой информации о том, как их создавать. Я считаю, что "контекст" для проверки атрибута - это класс, в котором живет атрибут. Вот почему я создаю контекст проверки с экземпляром класса в качестве первого параметра. Затем он предоставляет валидатору доступ к другим атрибутам класса, поэтому вы можете выполнить проверку атрибутов перекрестных ссылок.
Теперь, когда у меня есть созданный контекст и указатель на валидатор, я могу перейти непосредственно в unit test, чтобы убедиться, что валидатор выполняет свою работу должным образом:
[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(), как я сделал здесь.
Я надеюсь, что это поможет кому-то другому, кто может писать валидаторы, и так же религиозен в отношении модульного тестирования, как и я.:)
Вот хорошая статья о создании настраиваемых валидаторов.
Ответ 7
// You can do something like this.
[TestMethod]
public void PhoneNumberIsValid
{
var propInfo = typeof(Person).GetProperty("PhoneNumber");
var attr = propInfo.GetCustomAttributes(typeof(RegularExpressionAttribute), true);
// Act Assert Positives
Assert.IsTrue(((RegularExpressionAttribute)attr [0]).IsValid("555-55-5555"));
// Act Assert Negative
Assert.IsFalse(((RegularExpressionAttribute)attr[0]).IsValid("123654654654"));
}