Введение в лямбда-поведение

Введение в Lambda Behave

1. обзор

В этой статье мы обсудим новую платформу тестирования на основе Java под названиемLambda Behave.

Как следует из названия, эта среда тестирования предназначена для работы с Java 8 Lambdas. Далее в этой статье мы рассмотрим спецификации и рассмотрим пример для каждого.

Зависимость Maven, которую мы должны включить:


    com.insightfullogic
    lambda-behave
    0.4

Последнюю версию можно найтиhere.

2. основы

Одной из целей фреймворка является достижение высокой читабельности. Синтаксис побуждает нас описывать контрольные примеры, используя полные предложения, а не несколько слов.

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

3. Реализация теста Lambda Behave Test

Каждый набор спецификаций начинается сSuite.describe.. На данный момент у нас есть несколько встроенных методов для объявления нашей спецификации. Итак,Suite похож на тестовый класс JUnit, а спецификации похожи на методы, аннотированные@Test в JUnit.

Для описания теста мы используемshould().. Точно так же, если мы назовем лямбда-параметр ожидания как“expect”,, мы сможем сказать, какой результат мы ожидаем от теста, черезexpect.that().

Если мы хотим настроить или удалить какие-либо данные до и после спецификации, мы можем использоватьit.isSetupWith() иit.isConcludedWith().. Таким же образом, чтобы сделать что-то до и послеSuite, мы я буду использоватьit.initiatizesWith() иit.completesWith().

Давайте посмотрим на пример простой тестовой спецификации для классаCalculator:

public class Calculator {

    public int add() {
        return this.x + this.y;
    }

    public int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException();
        }
        return a / b;
    }
}

Начнем сSuite.describe, а затем добавим код для инициализацииCalculator.

Затем мы протестируем методadd(), написав спецификацию:

{
    Suite.describe("Lambda behave example tests", it -> {
        it.isSetupWith(() -> {
            calculator = new Calculator(1, 2);
        });

        it.should("Add the given numbers", expect -> {
            expect.that(calculator.add()).is(3);
        });
}

Здесь мы назвали переменные“it” и“expect” для лучшей читаемости. Поскольку это имена лямбда-параметров, мы можем заменить их на любые имена по нашему выбору.

Первый аргументshould() описывает, используя простой английский, что этот тест должен проверять. Второй аргумент - это лямбда, указывающая на наши ожидания, что методadd() должен вернуть 3.

Давайте добавим еще один тестовый пример для деления на 0 и проверим, получаем ли мы исключение:

it.should("Throw an exception if divide by 0", expect -> {
    expect.exception(ArithmeticException.class, () -> {
        calculator.divide(1, 0);
    });
});

В этом случае мы ожидаем исключения, поэтому мы указываемexpect.exception() и внутри него мы пишем код, который должен генерировать исключение.

Обратите внимание, что текстовое описание должно быть уникальным для каждой спецификации.

4. Спецификации на основе данных

Эта структура позволяет параметризацию теста на уровне спецификации.

Чтобы создать пример, давайте добавим метод в наш классCalculator:

public int add(int a, int b) {
    return a + b;
}

Давайте напишем для него тест на основе данных:

it.uses(2, 3, 5)
  .and(23, 10, 33)
  .toShow("%d + %d = %d", (expect, a, b, c) -> {
    expect.that(calculator.add(a, b)).is(c);
});

Методuses() используется для указания входных данных в разном количестве столбцов. Первые два аргумента - это параметры функцииadd(), а третий - ожидаемый результат. Эти параметры также могут быть использованы в описании, как показано в тесте.

toShow() используется для описания теста с использованием параметров - со следующим выходом:

0: 2 + 3 = 5 (seed: 42562700892554)(Lambda behave example tests)
1: 23 + 10 = 33 (seed: 42562700892554)(Lambda behave example tests)

5. Сгенерированные спецификации - Тестирование на основе свойств

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

Например, когда мы тестируем функцию реверсаString, мы можем проверить, что если мы дважды перевернем конкретныйString, мы получим исходныйString.

Property-Based testing focuses on the generic property without hard-coding specific test parameters. Этого можно добиться, используя случайно сгенерированные тестовые примеры.

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

Итак, наш тест на основе свойства разворотаString будет выглядеть так:

it.requires(2)
  .example(Generator.asciiStrings())
  .toShow("Reversing a String twice returns the original String",
    (expect, str) -> {
        String same = new StringBuilder(str)
          .reverse().reverse().toString();
        expect.that(same).isEqualTo(str);
   });

У нас есть метод_ indicated the number of required test cases using the _requires(). Мы используем предложениеexample(), чтобы указать, какие типы объектов нам нужны и как.

Выход для этой спецификации:

0: Reversing a String twice returns the original String(ljL+qz2)
  (seed: 42562700892554)(Lambda behave example tests)
1: Reversing a String twice returns the original String(g)
  (seed: 42562700892554)(Lambda behave example tests)

5.1. Детерминированная генерация тестовых примеров

Когда мы используем автоматически сгенерированные тестовые случаи, становится довольно трудно изолировать неудачные тесты. Например,if our functionality fails once in 1000 times, a specification that auto-generates just 10 cases, will have to be run over and over to observe the error.

Итак, нам нужна возможность детально детерминировать повторные тесты, включая ранее неудачные случаи.

Lambda Behave способен справиться с этой проблемой. Как показано в выходных данных предыдущего тестового примера, он печатает начальное число, которое использовалось для генерации случайного набора тестовых случаев. Итак, если что-то не удается,we can use the seed to re-create previously generated test cases.

Мы можем посмотреть на результат тестового примера и определить начальное значение:(seed: 42562700892554). Теперь, чтобы снова сгенерировать тот же набор тестов, мы можем использоватьSourceGenerator.

SourceGenerator содержит методdeterministicNumbers(), который принимает только начальное число в качестве аргумента:

 it.requires(2)
   .withSource(SourceGenerator.deterministicNumbers(42562700892554L))
   .example(Generator.asciiStrings())
   .toShow("Reversing a String twice returns the original String",
     (expect, str) -> {
       String same = new StringBuilder(str).reverse()
         .reverse()
         .toString();
       expect.that(same).isEqualTo(str);
});

Выполнив этот тест, мы получим тот же результат, что и ранее.

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

В этой статье мы увидели, как писать модульные тесты, используя лямбда-выражения Java 8, в новой свободно используемой среде тестирования, называемой Lambda Behave.

Как всегда, код для этих примеров можно найтиover on GitHub.