1. assert'и

Асерти (asserts) – це спеціальні перевірки, які можна вставити в різні місця коду. Їхнє завдання – визначати, що щось пішло не так. Точніше, перевіряти, що все йде як треба. Саме це "як треба" вони дозволяють вказати в різний спосіб.

Деякі асерти тобі вже зустрічалися. Перший – перевірка об'єктів на рівність. Якщо об'єкти не рівні - кинеться виняток і тест буде провалено.

Тут важливий порядок порівняння, адже JUnit у підсумковому звіті напише щось на кшталт “отримано значення 1, а очікувалося 3”. Загальний формат такої перевірки має вигляд:

assertEquals(еталон, значення)

Приклад:


@Test
public void whenAssertingEquality () {
    String expected = "3.1415";
    String actual = "3";

    assertEquals(expected, actual);
}

2. Методи assertEquals, assertTrue, assertFalse

Нижче я наведу список найпопулярніших методів – асертів. Завдяки їхнім назвам можна здогадатися, як вони працюють. Але все ж я напишу коротке пояснення:

assertEquals Перевіряє, що два об'єкти рівні
assertArrayEquals Перевіряє, що два масиви містять рівні значення
assertNotNull Перевіряє, що аргумент не дорівнює null
assertNull Перевіряє, що аргумент дорівнює null
assertNotSame Перевіряє, що два аргументи — це не той самий об'єкт.
assertSame Перевіряє, що два аргументи — це один і той самий об'єкт.
assertTrue Перевіряє, що аргумент дорівнює true
assertFalse Перевіряє, що аргумент дорівнює false

Деякі з цих методів видаються зайвими. Навіщо використовувати assertSame(a, b), якщо можна просто написати assertTrue(a == b)?

Справа в тому, що assert – це дуже розумний метод. Він робить багато чого корисного, в тому числі пише в лог інформацію про помилку. У першому випадку він напише, що очікувався об'єкт А, а отримано об'єкт Б. У другому випадку просто напише, що очікувалося true.

Коли в тебе сотні тестів, особливо якщо вони виконуються на спеціальному тестовому сервері, наявність детальних логів може бути суперкорисною. Думаю, ти розумієш, про що я.

Приклад порівняння масивів:


@Test
public void whenAssertingArraysEquality() {
    char[] expected = {'J','u','n','i','t'};
    char[] actual = "Junit".toCharArray();

    assertArrayEquals(expected, actual);
}

3. Метод assertAll

Як говорилося вище, метод assert не просто виконує перевірку, але й пише в лог багато інформації про об'єкти, що порівнюються.

Скажімо, виконується порівняння:


Address address = unitUnderTest.methodUnderTest();
assertEquals("Вашингтон", address.getCity());
assertEquals("Oracle Parkway", address.getStreet());
assertEquals("500", address.getNumber());

Але якщо один із параметрів не збігається, перевірка інших не відбудеться. А хотілося б, щоб вони все ж таки відбулися, і їх результати записалися в лог. Але водночас якщо хоча б одна перевірка не пройшла, то тест все ж був провалений.

Для цього є спеціальний метод – assertAll(). За перший аргумент він приймає коментар, який потрібно записати в лог, а далі — будь-яку кількість функцій-асертів.

Ось як перепишеться наш приклад з його допомогою:


Address address = unitUnderTest.methodUnderTest();
assertAll("Складний сценарій порівняння адреси",
    () -> assertEquals("Вашингтон", address.getCity()),
    () -> assertEquals("Oracle Parkway", address.getStreet()),
    () -> assertEquals("500", address.getNumber())
);

Тоді якщо адреса буде неправильною, в лог запишеться щось типу:

	Складний сценарій порівняння адреси (3 failures)
	expected: <Вашингтон> but was: <Сіетл>
    expected: <Oracle Parkway> but was: <Main Street>
    expected: <500> but was: <5772>

4. Метод assertTimeout

Пам'ятаєш анотацію @Timeout? Вона дозволяла контролювати час виконання всього методу. Але іноді буває корисно встановити обмеження виконання певної частини коду всередині методу. Для цього можна використовувати assertTimeout().

Як перший параметр у нього передається час, а як другий – код (функція), який повинен виконатися за вказаний час. Приклад:


@Test
public void whenAssertingTimeout() {
    assertTimeout(
  	ofSeconds(2),
  	() -> {
    	// пауза в одну секунду
    	Thread.sleep(1000);
  	}
	);
}

Клас Assert має 12 варіантів методу assertTimeout(). Якщо хочеш ознайомитися з ними докладніше, ласкаво просимо до офіційної документації.

5. Метод assertThrows

Дуже часто виникаються ситуації, коли тобі потрібно переконатися, що у певній ситуації код кидає необхідний виняток: визначив помилку та кинув потрібний виняток. Це дуже поширена ситуація.

На цей випадок є ще один корисний метод assertassert Throws (). Ось загальний формат його виклику:


assertThrows(виняток, код)

По суті він дуже схожий на метод assertTimeout(), тільки він перевіряє, щоб зазначений код кинув потрібний виняток. Приклад:


@Test
void whenAssertingException() {
    Throwable exception = assertThrows(
  	IllegalArgumentException.class,
  	() -> {
      	throw new IllegalArgumentException("Exception message");
  	}
    );
    assertEquals("Exception message", exception.getMessage());
}