Перейти к основному содержимому

Использование сопоставителей чисел Hamcrest

· 6 мин. чтения

1. Обзор

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

В этой статье мы углубимся в сопоставители чисел.

2. Настройка

Чтобы получить Hamcrest, нам просто нужно добавить следующую зависимость Maven в наш pom.xml :

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<version>2.0.0.0</version>
</dependency>

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

3. Сопоставители близости

Первый набор сопоставителей, который мы собираемся рассмотреть, — это те, которые проверяют, близок ли какой-либо элемент к значению +/- ошибка .

Более формально:

value - error <= element <= value + error

Если приведенное выше сравнение верно, утверждение пройдет.

Давайте посмотрим на это в действии!

3.1. isClose с двойными значениями

Допустим, у нас есть число, хранящееся в двойной переменной, называемой фактической. И мы хотим проверить , близко ли фактическое значение к 1 +/- 0,5.

То есть:

1 - 0.5 <= actual <= 1 + 0.5
0.5 <= actual <= 1.5

Теперь давайте создадим модульный тест, используя сопоставитель isClose :

@Test
public void givenADouble_whenCloseTo_thenCorrect() {
double actual = 1.3;
double operand = 1;
double error = 0.5;

assertThat(actual, closeTo(operand, error));
}

Поскольку 1,3 находится между 0,5 и 1,5, тест будет пройден. Таким же образом мы можем протестировать негативный сценарий:

@Test
public void givenADouble_whenNotCloseTo_thenCorrect() {
double actual = 1.6;
double operand = 1;
double error = 0.5;

assertThat(actual, not(closeTo(operand, error)));
}

Теперь давайте рассмотрим аналогичную ситуацию с другим типом переменных.

3.2. isClose со значениями BigDecimal

isClose перегружен и может использоваться так же, как и с двойными значениями, но с объектами BigDecimal :

@Test
public void givenABigDecimal_whenCloseTo_thenCorrect() {
BigDecimal actual = new BigDecimal("1.0003");
BigDecimal operand = new BigDecimal("1");
BigDecimal error = new BigDecimal("0.0005");

assertThat(actual, is(closeTo(operand, error)));
}

@Test
public void givenABigDecimal_whenNotCloseTo_thenCorrect() {
BigDecimal actual = new BigDecimal("1.0006");
BigDecimal operand = new BigDecimal("1");
BigDecimal error = new BigDecimal("0.0005");

assertThat(actual, is(not(closeTo(operand, error))));
}

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

Вот и все, что касается сопоставителей близости. Далее мы рассмотрим сопоставители ордеров.

4. Сопоставители заказов

Как следует из их названия, эти сопоставители помогают делать утверждения относительно порядка.

Их пять:

  • сравниваетEqualTo
  • лучше чем
  • больше или равно
  • меньше, чем
  • меньше или равно

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

4.1. Сопоставители порядка с целыми значениями

Наиболее распространенным сценарием будет использование этих сопоставителей с числами .

Итак, давайте продолжим и создадим несколько тестов:

@Test
public void given5_whenComparesEqualTo5_thenCorrect() {
Integer five = 5;

assertThat(five, comparesEqualTo(five));
}

@Test
public void given5_whenNotComparesEqualTo7_thenCorrect() {
Integer seven = 7;
Integer five = 5;

assertThat(five, not(comparesEqualTo(seven)));
}

@Test
public void given7_whenGreaterThan5_thenCorrect() {
Integer seven = 7;
Integer five = 5;

assertThat(seven, is(greaterThan(five)));
}

@Test
public void given7_whenGreaterThanOrEqualTo5_thenCorrect() {
Integer seven = 7;
Integer five = 5;

assertThat(seven, is(greaterThanOrEqualTo(five)));
}

@Test
public void given5_whenGreaterThanOrEqualTo5_thenCorrect() {
Integer five = 5;

assertThat(five, is(greaterThanOrEqualTo(five)));
}

@Test
public void given3_whenLessThan5_thenCorrect() {
Integer three = 3;
Integer five = 5;

assertThat(three, is(lessThan(five)));
}

@Test
public void given3_whenLessThanOrEqualTo5_thenCorrect() {
Integer three = 3;
Integer five = 5;

assertThat(three, is(lessThanOrEqualTo(five)));
}

@Test
public void given5_whenLessThanOrEqualTo5_thenCorrect() {
Integer five = 5;

assertThat(five, is(lessThanOrEqualTo(five)));
}

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

4.2. Сопоставители ордеров со строковыми значениями

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

Давайте посмотрим несколько примеров со строками:

@Test
public void givenBenjamin_whenGreaterThanAmanda_thenCorrect() {
String amanda = "Amanda";
String benjamin = "Benjamin";

assertThat(benjamin, is(greaterThan(amanda)));
}

@Test
public void givenAmanda_whenLessThanBenajmin_thenCorrect() {
String amanda = "Amanda";
String benjamin = "Benjamin";

assertThat(amanda, is(lessThan(benjamin)));
}

Строка реализует алфавитный порядок в методе compareTo интерфейса Comparable .

Итак, имеет смысл, что слово «Аманда» предшествует слову «Бенджамин».

4.3. Сопоставители заказов со значениями LocalDate

Как и в случае со строками , мы можем сравнивать даты. Давайте посмотрим на те же примеры, которые мы создали выше, но с использованием объектов LocalDate :

@Test
public void givenToday_whenGreaterThanYesterday_thenCorrect() {
LocalDate today = LocalDate.now();
LocalDate yesterday = today.minusDays(1);

assertThat(today, is(greaterThan(yesterday)));
}

@Test
public void givenToday_whenLessThanTomorrow_thenCorrect() {
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);

assertThat(today, is(lessThan(tomorrow)));
}

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

4.4. Сопоставители заказов с пользовательскими классами

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

Начнем с создания bean-компонента Person :

public class Person {
String name;
int age;

// standard constructor, getters and setters
}

Теперь давайте реализуем Comparable :

public class Person implements Comparable<Person> {

// ...

@Override
public int compareTo(Person o) {
if (this.age == o.getAge()) return 0;
if (this.age > o.getAge()) return 1;
else return -1;
}
}

Наша реализация compareTo сравнивает двух людей по их возрасту. Давайте теперь создадим пару новых тестов:

@Test
public void givenAmanda_whenOlderThanBenjamin_thenCorrect() {
Person amanda = new Person("Amanda", 20);
Person benjamin = new Person("Benjamin", 18);

assertThat(amanda, is(greaterThan(benjamin)));
}

@Test
public void
givenBenjamin_whenYoungerThanAmanda_thenCorrect() {
Person amanda = new Person("Amanda", 20);
Person benjamin = new Person("Benjamin", 18);

assertThat(benjamin, is(lessThan(amanda)));
}

Сопоставители теперь будут работать на основе нашей логики compareTo .

5. Сопоставитель NaN

Hamcrest предоставляет один дополнительный сопоставитель чисел, чтобы определить, является ли число на самом деле числом :

@Test
public void givenNaN_whenIsNotANumber_thenCorrect() {
double zero = 0d;

assertThat(zero / zero, is(notANumber()));
}

6. Выводы

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

Более того, сопоставители Hamcrest в целом не требуют пояснений и легко читаются .

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

Полную реализацию примеров из этой статьи можно найти на GitHub .