Зарегистрируйтесь, чтобы продолжить обучение

Матчеры Java: Автоматическое тестирование

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

Матчеры стали популярны в тестовых фреймворках после появления подхода BDD (Behaviour Driven Development, разработка через поведение). Технически, такой подход стремится сделать тесты похожими на словесное описание выполняемой задачи. Это даёт возможность использовать их как документацию людям, которые не умеют программировать (В идеале, на практике всё сложнее). Матчеры заменили собой обычные утверждения на функциях во многих языках:

int[] a = {1, 2, 3};
int[] b = {1, 2, 3};

// Проверка равенства по ссылке
// assert a == b;
assertThat(a).isSameAs(b); // false

// Проверка равенства по значению
// assert Arrays.equals(a, b);
assertThat(a).isEqualTo(b); // true

Любой матчер в AssertJ начинается с метода assertThat(data), в которую передаются данные на проверку. Затем assertThat возвращает специальный объект, у которого уже можно вызывать различные матчеры для проверки. В AssertJ десятки матчеров для самых разнообразных ситуаций. Такое количество объясняется желанием выдавать максимально точный отчёт о том что произошло.

Предположим, что метод возвращает массив и мы хотим проверить его размер. Для этого можно воспользоваться матчером isEqualTo:

int[] data = {1, 2, 3};

// take берет первые n элементов
// assert.equal(take(data, 2).length, 2)
assertThat(ArrayUtils.take(data, 2).length).isEqualTo(3);

Этот матчер прекрасно справится с задачей. Но в случае ошибки его вывод не слишком информативен:

Expecting:
 <2>
to be equal to:
 <3>
but was not.

Поэтому лучше взять специализированный матчер для проверки размера массива:

assertThat(take(data, 2)).hasSize(3);

Тогда вывод расскажет гораздо больше:

Expected size:<3> but was:<2> in:
<[1, 2]>

Благодаря тому, что в assertThat() передаётся сам массив, а не его длина, у AssertJ появляется возможность выводить содержимое массива в случае ошибки. Это, опять же, упрощает отладку.

Ниже пример некоторых популярных матчеров, полезных в ежедневном тестировании:

char[] data = {'a', 'b', 'c'};
// проверка, что размеры объектов совпадают
assertThat(data).hasSameSizeAs(new int[] {1, 2, 3});
// проверка, что не null
assertThat(data).isNotNull();
// проверка, что выражение равно true
assertThat(true).isTrue();
// проверка, что объект находится в перечне
assertThat(1).isIn(1, 2, 3, 4);
// проверка, что число находится в отрезке [a, b]
assertThat(9).isBetween(9, 11);
// проверка, что число находится в интервале (a, b)
assertThat(10).isStrictlyBetween(9, 11);

Кроме того, практически все матчеры обладают как "позитивной" так и "негативной" версией:

assertThat(data).isNull();
assertThat(data).isNotNull();

assertThat(true).isTrue();
assertThat(false).isFalse();

assertThat(1).isIn(1, 2, 3, 4);
assertThat(1).isNotIn(2, 3, 4, 5);

Отдельно стоит выделить матчеры, которые работают с экземплярами классов. Для Java, как для ООП-языка, это особенно важно. В AssertJ есть матчеры, которые могут "обходить" переданные экземпляры классов и сравнивать их по отдельным полям.

// сравнение по ссылке
assertThat(obj1).isEqualTo(obj1);
// Каждое поле одного объекта сравнивается с соответствующим полем другого.
assertThat(obj1).isEqualToComparingFieldByField(obj2);

// далее рассмотрим только названия методов
// сравниваем, игнорируя поля, равные null
.isEqualToIgnoringNullFields()
// сравниваем только по указанному перечню полей
.isEqualToComparingOnlyGivenFields()
// все поля объекта равны null
.hasAllNullFieldsOrProperties()

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

Библиотека AssertJ позволяет собирать несколько тестов в один вызов:

public static void testMethod() {
    var a = "Hello, world!";
    assertThat(a)                // утверждаем, что:
            .startsWith("Hello") // строка начинается с подстроки "Hello"
            .contains("llo, ")   // содержит строку "llo, "
            .endsWith("!");      // заканчивается строкой "!"
    }

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


Дополнительные материалы

  1. Документация AssertJ

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Для полного доступа к курсу нужен базовый план

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

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
Научитесь разработке веб-приложений, сайтов и программного обеспечения на языке Java, программируйте и используйте структуры данных
10 месяцев
с нуля
Старт 5 декабря

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»