Пример тестирования свойств с помощью Vavr

Пример тестирования свойства с Vavr

1. обзор

В этой статье мы рассмотрим концепциюProperty Testing и ее реализацию в библиотекеvavr-test..

Property based testing (PBT) позволяет нам определять высокоуровневое поведение программы в отношении инвариантов, которых она должна придерживаться.

2. Что такое проверка собственности?

Свойство - это комбинация инварианта сinput values generator. Для каждого сгенерированного значения инвариант обрабатывается как предикат и проверяется, дает ли он значение true или false для этого значения.

Как только есть одно значение, которое возвращает false, свойство считается фальсифицированным, и проверка отменяется. Если свойство не может быть признано недействительным после определенного количества выборочных данных, свойство считается выполненным.

Благодаря такому поведению наш тест не проходит быстро, если условие не выполняется без выполнения ненужной работы.

3. Maven Dependency

Во-первых, нам нужно добавить зависимость Maven в библиотекуvavr-test:


    io.vavr
    jvavr-test
    ${vavr.test.version}



    2.0.5

4. Написание тестов на основе свойств

Давайте рассмотрим функцию, которая возвращает поток строк. Это бесконечный поток от 0 вверх, который отображает числа в строки на основе простого правила. Мы используем здесь интересную функцию Vavr, называемуюPattern Matching:

private static Predicate divisibleByTwo = i -> i % 2 == 0;
private static Predicate divisibleByFive = i -> i % 5 == 0;

private Stream stringsSupplier() {
    return Stream.from(0).map(i -> Match(i).of(
      Case($(divisibleByFive.and(divisibleByTwo)), "DividedByTwoAndFiveWithoutRemainder"),
      Case($(divisibleByFive), "DividedByFiveWithoutRemainder"),
      Case($(divisibleByTwo), "DividedByTwoWithoutRemainder"),
      Case($(), "")));
}

Написание модульного теста для такого метода будет подвержено ошибкам, потому что велика вероятность того, что мы забудем о каком-то крайнем случае и не охватим все возможные сценарии.

К счастью, мы можем написать тест на основе свойств, который будет охватывать все крайние случаи для нас. Во-первых, нам нужно определить, какие числа должны быть входными данными для нашего теста:

Arbitrary multiplesOf2 = Arbitrary.integer()
  .filter(i -> i > 0)
  .filter(i -> i % 2 == 0 && i % 5 != 0);

Мы указали, что входное число должно удовлетворять двум условиям - оно должно быть больше нуля и должно делиться на два без остатка, но не на пять.

Далее нам нужно определить условие, которое проверяет, возвращает ли проверяемая функция правильное значение для данного аргумента:

CheckedFunction1 mustEquals
  = i -> stringsSupplier().get(i).equals("DividedByTwoWithoutRemainder");

Чтобы начать тест на основе свойств, нам нужно использовать классProperty:

CheckResult result = Property
  .def("Every second element must equal to DividedByTwoWithoutRemainder")
  .forAll(multiplesOf2)
  .suchThat(mustEquals)
  .check(10_000, 100);

result.assertIsSatisfied();

Мы указываем, что для всех произвольных целых чисел, кратных 2, должен выполняться предикатmustEquals. Методcheck() принимает размер сгенерированных входных данных и количество запусков этого теста.

Мы можем быстро написать еще один тест, который проверит, возвращает ли функцияstringsSupplier()DividedByTwoAndFiveWithoutRemainder string для каждого входного числа, которое делится на два и пять без остатка.

Необходимо изменить поставщикаArbitrary иCheckedFunction:

Arbitrary multiplesOf5 = Arbitrary.integer()
  .filter(i -> i > 0)
  .filter(i -> i % 5 == 0 && i % 2 == 0);

CheckedFunction1 mustEquals
  = i -> stringsSupplier().get(i).endsWith("DividedByTwoAndFiveWithoutRemainder");

Затем мы можем запустить тест на основе свойств для тысячи итераций:

Property.def("Every fifth element must equal to DividedByTwoAndFiveWithoutRemainder")
  .forAll(multiplesOf5)
  .suchThat(mustEquals)
  .check(10_000, 1_000)
  .assertIsSatisfied();

5. Заключение

В этой быстрой статье мы взглянули на концепцию тестирования на основе свойств.

Мы создали тесты с использованием библиотеки vavr-test; мы использовали классыArbitrary, CheckedFunction, иProperty для определения теста на основе свойств с использованиемvavr-test.

Реализацию всех этих примеров и фрагментов кода можно найти вover on GitHub - это проект Maven, поэтому его должно быть легко импортировать и запускать как есть.