Подтвердить что ты не робот

Как вызвать атрибут проверки для тестирования?

Я использую функцию 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);
4b9b3361

Ответ 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"));

        }