пятница, 18 февраля 2011 г.

Новая constraint based модель проверок NUnit Framework

В данной статье я расскажу про новую модель проверок на основе constraints, которая   поможет сделать тесты лучше
                                                Constraint based model
Старая модель проверок основывалась на классе Assert, который имеет набор статических перегруженных методов для проверки различных условий. К примеру, при этом подходе тесты выглядят так:
    [Test]
        public void TraditionalAssertModelTest()
        {
           
            string result = "Asd" + 3;
           
            Assert.AreEqual("asd3", result.ToLower());
        }

Статический метод  AreEqual имеет довольно много перегрузок, что не очень удобно. Новая же модель проверок использует один метод для всех проверок. Вот пример аналогичного теста с использованием новой модели:

        [Test]
        public void NewConstraintModel()
        {
            string result = "Asd" + 3;
            Assert.That(result, new EqualConstraint("asd3").IgnoreCase);
        }

Для каждой проверки есть отдельный класс constraint, который инкапсулирует в себе логику проверки. В данном случае это EqualConstraint переданный в метод как второй параметр.  Также constrains имеют различные модификаторы как в примере IgnoreCase. Модификаторы служат для того чтобы указать дополнительные параметры проверки.
В NUnit включены специальные вспомогательные классы, такие как Is и Has, которые помогают писать проверки в более читабельном формате  
        [Test]
        public void NewConstraintModelSyntaxHelper()
        {
            string result = "Asd" + 3;

            Assert.That(result, Is.EqualTo("asd3").IgnoreCase);
        }

NUnit позволяет создавать собственные классы constraints для этого нужно, чтобы класс реализовывал интерфейс IConstraint.
Из преимуществ  использования данной модели проверок можно выделить следующие:
    Тесты более легко читать и понимать.
   Написание проверок более легкое по сравнению с использованием AreEqual  со множеством перегрузок.
Использование отдельных классов constraints для проверок соблюдается разделение ответственности. Каждый класс ответственен за одну проверку.
Давайте рассмотрим на примерах новые constraint.
 String Constraints
        [Test]
        public void StringConstraintTest()
        {
            Assert.That("abc", Is.StringContaining("a"));
            Assert.That("abc", Is.StringStarting("a"));
            Assert.That("abc", Is.StringEnding("c"));
        }

                                                               Range Constraint
Range Constraint позволяет проверить если значение лежит в определенном интервале:
       Assert.That(4, Is.InRange(1, 6));

       тоже самое что и:

      Assert.That(4, Is.GreaterThanOrEqualTo(1).And.LessThanOrEqualTo(6));

                     Type Constraints

        internal class A
        {
        }

        internal class B : A
        {
        }

        [Test]
        public void TypeConstraintTest()
        {
            A a = new A();
            B b = new B();
            Assert.That(a, Is.TypeOf<A>());
            Assert.That(a, Is.Not.TypeOf<B>());
            Assert.That(b, Is.InstanceOf<A>());
            Assert.That(b, Is.AssignableTo<A>());
        }

TypeOf – проверяет если объект точно типа A.

InstanceOf – проверяет если объект типа A.
AssignableTo – проверяет если объект сопоставим с типом A

Throws Constraints
        [Test]
        public void ThrowsExceptionConstraintTest()
        {
            Assert.That(
                () => { new MyClass(null); },
                Throws.InstanceOf<ArgumentNullException>()
                .And.Message.Contains("myparameter"));
        }

 Throws Constraints  служат для проверки если определенный метод сгенерировал исключение.
Раньше надо было использовать атрибуты:

       [ExpectedException(
        ExpectedException = typeof(ArgumentNullException),
        ExpectedMessage = "myparameter",
        MatchType = MessageMatch.Contains)]
        public void OldStyleThrowException()
        {

            new MyClass(null);

        }

Collections Constraints
Данные constrains позволяют проверять коллекции объектов. Например, если коллекция упорядочена по определенному полю, есть ли в коллекции определенный объект.

        [Test]
        public void CollectionConastraints()
        {
            int[] array = new int[] { 1, 2, 3, 4, 5 };

            Assert.That(array, Is.Unique);
            Assert.That(array, Has.Length.LessThan(10));
            Assert.That(array, Is.All.LessThan(6));
            Assert.That(array, Is.Ordered);
        }
Unique-  проверяет если в коллекции все элементы уникальны
Ordered- проверяет если коллекция упорядочена

 public class MyClass
 {       
     public int Property { get; set; }
 }





 [Test]
        public void CollectionConstrainsComplexTypes()
        {
            MyClass[] array = new[]
                                  {new MyClass {Property = 1},
                                   new MyClass {Property = 2},
                                   new MyClass {Property = 3}};

            Assert.That(array, Is.Ordered.By("Property"));
        }


Delayed Constraints
Delayed Constraint позволяет проверить какое-либо условие через определенный промежуток времени.  Например:
   [Test]
   public void Stop_Elapsed()
   {
     //Arange
     StopWatch stopWatch = new StopWatch();
     stopWatch.Start();
     //Act
     Thread.Sleep(1000);
     //Assert
     Assert.That(stopWatch.ElapsedMilliseconds,Is.EqualTo(1000).After(1020));
   }

Данный constraint можно применять также для проверки методов, которые вызываются асинхронно
Я надеюсь, этот пост будет полезен разработчикам которые пишут тесты с использованием
NUnit  Framework и не только им.
Более детальную информацию о NUnit можно найти на сайте http://www.nunit.com/

Комментариев нет:

Отправить комментарий