Сьогодні ми вивчимо основи Unit-тестування з використанням JUnit 5.
Давай розберемося, як використати цю силу для створення якісного й безпечного коду.
Що таке JUnit 5 і навіщо він потрібен?
JUnit 5 — це сучасна версія популярного фреймворка для тестування на Java. Його мета — допомогти розробникам писати якісні Unit-тести. Перевага JUnit 5 полягає в його модульності та гнучкості. Ось основні компоненти JUnit 5:
- JUnit Platform: відповідає за запуск тестів.
- JUnit Jupiter: надає нові функції та анотації для тестування.
- JUnit Vintage: дозволяє запускати старі тести, написані на JUnit 3 і 4 (археологи, це для вас).
Чому JUnit 5? Бо:
- Підтримує Java 8 і вище, включно з лямбдами та методами за замовчуванням.
- Більше можливостей для налаштування життєвого циклу тестів.
- Зручніша анотація
@DisplayName, щоб твої тести виглядали красиво і зрозуміло.
Основні анотації JUnit 5
Анотації — це як вказівки для JUnit, які повідомляють йому, що і як тестувати.
@Test
Найголовніша анотація. Якщо ти хочеш, щоб код виконався як тест, просто познач метод цією анотацією.
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class MathTest {
@Test
void additionTest() {
int result = 2 + 3;
assertEquals(5, result, "2 + 3 має дорівнювати 5");
}
}
@BeforeEach и @AfterEach
Використовуються для виконання дій до і після кожного тесту. Наприклад, налаштування тестового середовища або очищення ресурсів.
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;
class LifecycleTest {
@BeforeEach
void setUp() {
System.out.println("Підготовка перед тестом");
}
@AfterEach
void tearDown() {
System.out.println("Очищення після тесту");
}
@Test
void simpleTest() {
System.out.println("Виконання тесту");
}
}
Виводи будуть такі:
Підготовка перед тестом
Виконання тесту
Очищення після тесту
@BeforeAll и @AfterAll
Використовуються для виконання дій до або після всіх тестів у класі. Ці методи повинні бути static.
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.AfterAll;
class GlobalSetupTest {
@BeforeAll
static void init() {
System.out.println("Підготовка перед ВСІМИ тестами");
}
@AfterAll
static void cleanup() {
System.out.println("Очищення після ВСІХ тестів");
}
@Test
void testOne() {
System.out.println("Перший тест");
}
@Test
void testTwo() {
System.out.println("Другий тест");
}
}
Вивід:
Підготовка перед ВСІМИ тестами
Перший тест
Другий тест
Очищення після ВСІХ тестів
@DisplayName
Додай рослину в цифрову пустелю своїх тестів! Зроби їх гарнішими з @DisplayName.
@Test
@DisplayName("Перевірка додавання: 2 + 2 = 4")
void additionTest() {
assertEquals(4, 2 + 2);
}
Основні Assertions
Assertions — це як контрольні точки. Вони перевіряють, чи правильно працює твій код.
| Assertion | Опис | Приклад |
|---|---|---|
assertEquals(expected, actual) |
Перевіряє, чи рівні очікуване і фактичне | assertEquals(4, 2 + 2) |
assertNotEquals(unexpected, actual) |
Перевіряє, що значення НЕ рівні | assertNotEquals(5, 2 + 2) |
assertTrue(condition) |
Підтверджує, що умова істинна | assertTrue(2 + 2 == 4) |
assertFalse(condition) |
Підтверджує, що умова хибна | assertFalse(2 + 2 == 5) |
assertNull(object) |
Перевіряє, що об'єкт дорівнює null | assertNull(nullVariable) |
assertNotNull(object) |
Перевіряє, що об'єкт НЕ дорівнює null | assertNotNull(nonNullVariable) |
assertThrows(exception, lambda) |
Перевіряє, що код викликає вказане виключення | assertThrows(NumberFormatException.class, () -> Integer.parseInt("NaN")) |
Приклад:
@Test
void testAssertions() {
assertEquals(4, 2 + 2, "Додавання двох чисел повинно бути коректним");
assertTrue(3 > 2, "3 більше за 2 - це правда");
assertThrows(ArithmeticException.class, () -> {
int result = 10 / 0;
}, "Очікувалось ArithmeticException при діленні на 0");
}
Життєвий цикл тестів у JUnit 5
Тести в JUnit проходять через визначений життєвий цикл:
- Створюється об'єкт тестового класу.
- Викликається метод з анотацією @BeforeEach.
- Виконується тест.
- Викликається метод з анотацією @AfterEach.
- Повторюється для кожного тесту.
Методи з анотаціями @BeforeAll і @AfterAll виконуються один раз на весь клас.
Практика: Написання Unit-тестів для простих методів
Припустимо, у нас є клас Calculator:
class Calculator {
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
return a - b;
}
int multiply(int a, int b) {
return a * b;
}
int divide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Ділення на нуль не допускається");
}
return a / b;
}
}
І тести до нього:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
Calculator calculator = new Calculator();
@Test
void testAddition() {
assertEquals(5, calculator.add(2, 3), "2 + 3 має дорівнювати 5");
}
@Test
void testSubtraction() {
assertEquals(1, calculator.subtract(3, 2), "3 - 2 має дорівнювати 1");
}
@Test
void testMultiplication() {
assertEquals(6, calculator.multiply(2, 3), "2 * 3 має дорівнювати 6");
}
@Test
void testDivision() {
assertEquals(2, calculator.divide(6, 3), "6 / 3 має дорівнювати 2");
}
@Test
void testDivisionByZero() {
Exception exception = assertThrows(IllegalArgumentException.class, () -> calculator.divide(5, 0));
assertEquals("Ділення на нуль не допускається", exception.getMessage());
}
}
Ці тести перевіряють основні арифметичні операції і обробляють виключення при діленні на нуль.
Що найчастіше ставить людей у замішання?
- Чому тести не запускаються? Можливо, твій метод у тестовому класі не позначений
@Test. - Чому тест «падає»? Уважно прочитай повідомлення про помилку. Скоріше за все, очікування
assertEqualsне збігаються з фактичним результатом. - Як писати тести до приватних методів? Часто приватні методи тестуються опосередковано через публічні.
JUnit 5 — потужний інструмент, і чим більше ти з ним практикуєшся, тим простіше писати якісні тести. Вперед — ламай свої баги в найкращих традиціях супергероїв!
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ