JUnit: быстрый гайд

Если вы новичок в JUnit или просто хотите освежить свои знания, этот пост расскажет вам об основах JUnit в простой и понятной форме. Независимо от того, работаете ли вы с JUnit 4 или JUnit 5, это руководство поможет вам.

Что такое JUnit

Популярный фреймворк тестирования для Java. Он помогает разработчикам писать и выполнять тесты, чтобы убедиться, что их код работает так, как ожидается. Тесты пишутся в отдельном пакете «test» в вашем проекте, а JUnit предоставляет аннотации, чтобы облегчить тестирование.

Основные аннотации в JUnit

1. @Test

Самая важная аннотация. Она сообщает JUnit, что данный метод является тестовым.

@Test
public void testMethod() {
    // Your test logic here
}

2. @BeforeClass

Этот метод запускается один раз перед всеми тест-кейсами. Он полезен для задач настройки, таких как инициализация ресурсов.

@BeforeClass
public static void init() {
    System.out.println("Hello Test");
    System.out.println("Test runs at " + new Date());
}

3. @AfterClass

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

@AfterClass
public static void cleanup() {
    System.out.println("All tests are done!");
}

Пример, иллюстрирующий каждую аннотацию:

import org.junit.*;

public class BeforeAfterClassExample {

    @BeforeClass
    public static void setUpClass() {
        System.out.println("This runs ONCE BEFORE all test cases.");
        System.out.println("Example: Opening a database connection.");
    }

    @AfterClass
    public static void tearDownClass() {
        System.out.println("This runs ONCE AFTER all test cases.");
        System.out.println("Example: Closing the database connection.");
    }

    @Test
    public void testCase1() {
        System.out.println("Running test case 1.");
    }

    @Test
    public void testCase2() {
        System.out.println("Running test case 2.");
    }
}

Вывод:

This runs ONCE BEFORE all test cases.
Example: Opening a database connection.
Running test case 1.
Running test case 2.
This runs ONCE AFTER all test cases.
Example: Closing the database connection.

4. @Before

Этот метод запускается перед каждым тест-кейсом. Он отлично подходит для сброса условий перед каждым тестом.

@Before
public void setUp() {
    System.out.println("Setting up for a test...");
}

5. @After

Этот метод запускается после каждого тест-кейса. Используйте его для очистки после каждого теста.

@After
public void tearDown() {
    System.out.println("Cleaning up after a test...");
}

Пример, иллюстрирующий каждую аннотацию:

import org.junit.*;

public class BeforeAfterExample {

    @Before
    public void setUp() {
        System.out.println("This runs BEFORE EACH test case.");
        System.out.println("Example: Initializing test data.");
    }

    @After
    public void tearDown() {
        System.out.println("This runs AFTER EACH test case.");
        System.out.println("Example: Cleaning up test data.");
    }

    @Test
    public void testCase1() {
        System.out.println("Running test case 1.");
    }

    @Test
    public void testCase2() {
        System.out.println("Running test case 2.");
    }
}

Вывод:

This runs BEFORE EACH test case.
Example: Initializing test data.
Running test case 1.
This runs AFTER EACH test case.
Example: Cleaning up test data.

This runs BEFORE EACH test case.
Example: Initializing test data.
Running test case 2.
This runs AFTER EACH test case.
Example: Cleaning up test data.

Пример со всеми аннотациями:

Вот пример, в котором сочетаются @BeforeClass, @AfterClass, @Before и @After:

import org.junit.*;

public class CombinedBeforeAfterExample {

    @BeforeClass
    public static void setUpClass() {
        System.out.println("This runs ONCE BEFORE all test cases.");
        System.out.println("Example: Setting up global resources.");
    }

    @AfterClass
    public static void tearDownClass() {
        System.out.println("This runs ONCE AFTER all test cases.");
        System.out.println("Example: Releasing global resources.");
    }

    @Before
    public void setUp() {
        System.out.println("This runs BEFORE EACH test case.");
        System.out.println("Example: Preparing test data.");
    }

    @After
    public void tearDown() {
        System.out.println("This runs AFTER EACH test case.");
        System.out.println("Example: Cleaning up test data.");
    }

    @Test
    public void testCase1() {
        System.out.println("Running test case 1.");
    }

    @Test
    public void testCase2() {
        System.out.println("Running test case 2.");
    }
}

Вывод:

This runs ONCE BEFORE all test cases.
Example: Setting up global resources.

This runs BEFORE EACH test case.
Example: Preparing test data.
Running test case 1.
This runs AFTER EACH test case.
Example: Cleaning up test data.

This runs BEFORE EACH test case.
Example: Preparing test data.
Running test case 2.
This runs AFTER EACH test case.
Example: Cleaning up test data.

This runs ONCE AFTER all test cases.
Example: Releasing global resources.

6. @Test(timeout)

Эта аннотация гарантирует, что тест не займет слишком много времени. Если он превышает указанное время (в миллисекундах), тест падает.

@Test(timeout = 2000)
public void testTimeout() {
    // Test logic here
}

Что нового в JUnit 5

JUnit 5 — это последняя версия, в которой появилось несколько новых возможностей. Она состоит из трех частей:

  1. Платформа JUnit: Запускает тесты на JVM.
  2. JUnit Jupiter: Предоставляет новые аннотации и возможности.
  3. JUnit Vintage: Поддерживает старые тесты JUnit 3 и 4.

Новые аннотации в JUnit 5:

1. @BeforeAll

Заменяет @BeforeClass. Выполняется один раз перед всеми тест-кейсами.

@BeforeAll
public static void init() {
    System.out.println("Initializing tests...");
}

2. @AfterAll

Заменяет @AfterClass. Выполняется один раз после всех тест-кейсов.

@AfterAll
public static void cleanup() {
    System.out.println("Tests are complete!");
}

3. @BeforeEach

Заменяет @Before. Выполняется перед каждым тест-кейсом.

@BeforeEach
public void setUp() {
    System.out.println("Preparing for a test...");
}

4. @AfterEach

Заменяет @After. Выполняется после каждого тест-кейса.

@AfterEach
public void tearDown() {
    System.out.println("Cleaning up...");
}

5. @DisplayName

Аннотация @DisplayName позволяет давать тест-кейсам кастомные, удобочитаемые имена. Это делает репорты о тестировании более описательными и понятными.

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class DisplayNameExampleTest {

    @Test
    @DisplayName("Check if two numbers are equal")
    public void testEquals() {
        assertEquals(10, 5 + 5, "5 + 5 should equal 10");
    }

    @Test
    @DisplayName("Verify if a string is empty")
    public void testStringIsEmpty() {
        String str = "";
        assertTrue(str.isEmpty(), "The string should be empty");
    }

    @Test
    @DisplayName("Ensure array contains correct elements")
    public void testArrayContents() {
        int[] actual = {1, 2, 3};
        int[] expected = {1, 2, 3};
        assertArrayEquals(expected, actual, "Arrays should match");
    }
}

Вывод в отчетах:

При выполнении этих тестов в результатах тестирования вместо имени метода будет отображаться @DisplayName. Например:

  • Вместо testEquals() вы увидите: «Проверить, равны ли два числа».
  • Вместо testStringIsEmpty() вы увидите: «Проверить, пуста ли строка».

6. @Disabled

Пропускает тест-кейс.

@Test
@Disabled("This test is not ready yet")
public void skippedTest() {
    // Test logic here
}

7. @Tag

Аннотация @Tag используется для группировки связанных тестов. Это особенно полезно, когда вы хотите запустить определенные группы тестов (например, «Регрессия», «Дымовые», «Интеграционные»), не запуская весь набор.

  • Назначение: Используется для группировки или категоризации тестов.
  • Пример использования: помогает организовать тесты в логические группы (например, «Регрессия», «Дым», «Интеграция»), чтобы можно было запускать специальные наборы.
  • Пример: Если у вас есть 100 тестов, вы можете пометить 20 из них как «Дымовые» и запускать только эти тесты по мере необходимости.
  • Ключевой момент: Теги функциональны и используются для фильтрации тестов.
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class TagExampleTest {

    @Test
    @Tag("Regression")
    public void testAddition() {
        assertEquals(5, 2 + 3, "2 + 3 should equal 5");
    }

    @Test
    @Tag("Smoke")
    public void testSubtraction() {
        assertEquals(2, 5 - 3, "5 - 3 should equal 2");
    }

    @Test
    @Tag("Integration")
    public void testMultiplication() {
        assertEquals(15, 5 * 3, "5 * 3 should equal 15");
    }
}

Как запускать тесты с тегами:

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

Maven:

mvn test -Dgroups="Regression"

Gradle:

./gradlew test - tests "*TagExampleTest" -PincludeTags="Regression"

IDE (IntelliJ/Eclipse):

Большинство IDE позволяют фильтровать тесты по тегам в тест-раннере.

Комбинирование @Tag и @DisplayName

Вы можете использовать обе аннотации вместе, чтобы сделать ваши тесты еще более организованными и читаемыми.

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

public class CombinedExampleTest {

    @Test
    @Tag("Regression")
    @DisplayName("Test addition of two positive numbers")
    public void testPositiveAddition() {
        assertEquals(8, 3 + 5, "3 + 5 should equal 8");
    }

    @Test
    @Tag("Smoke")
    @DisplayName("Test subtraction with negative result")
    public void testNegativeSubtraction() {
        assertEquals(-2, 3 - 5, "3 - 5 should equal -2");
    }

    @Test
    @Tag("Integration")
    @DisplayName("Check if a list contains specific items")
    public void testListContents() {
        assertTrue(List.of(1, 2, 3).contains(2), "List should contain 2");
    }
}

Выполнение тестов с тегами и отображаемыми именами

При выполнении приведенных выше тестов вывод будет выглядеть примерно так:

CombinedExampleTest
  ✔ Test addition of two positive numbers [Regression]
  ✔ Test subtraction with negative result [Smoke]
  ✔ Check if a list contains specific items [Integration]

Утверждения в JUnit:

Утверждения используются для проверки соответствия фактического результата ожидаемому. Вот некоторые распространенные утверждения:

1. assertArrayEquals

Проверяет, равны ли два массива.

int[] actual = {1, 2, 3, 4};
int[] expected = {1, 2, 3, 4};
Assertions.assertArrayEquals(expected, actual);

2. assertEquals

Проверяет, равны ли два значения.

Assertions.assertEquals(5, 2 + 3);

3. assertTrue / assertFalse

Проверяет, истинно или ложно условие.

Assertions.assertTrue(10 > 5);
Assertions.assertFalse(10 < 5);

4. assertNull / assertNotNull

Проверяет, является ли объект нулевым или не нулевым.

String str = null;
Assertions.assertNull(str);
Assertions.assertNotNull("Hello");

5. assertThrows

Проверяет, было ли выброшено определенное исключение.

Assertions.assertThrows(RuntimeException.class, () -> {
    throw new RuntimeException();
});

Чем хорош JUnit?

  • Повышает качество кода: Тесты помогают выявить ошибки на ранней стадии.
  • Экономия времени: автоматизированные тесты быстрее, чем ручное тестирование.
  • Простота использования: Аннотации упрощают написание тестов.
  • Поддержка CI/CD: хорошо интегрируется с такими инструментами, как Jenkins.

Резюме

Независимо от того, используете ли вы JUnit 4 или 5, аннотации и утверждения упрощают написание и управление тестами.

Medium

Какой была ваша первая зарплата в QA и как вы искали первую работу?

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

Мы в Telegram

Наш официальный канал
Полезные материалы и тесты
Готовимся к собеседованию
Project- и Product-менеджмент

? Популярное

? Telegram-обсуждения

Наши подписчики обсуждают, как искали первую работу в QA. Некоторые ищут ее прямо сейчас.
Наши подписчики рассказывают о том, как не бояться задавать тупые вопросы и чувствовать себя уверенно в новой команде.
Обсуждаем, куда лучше податься - в менеджмент или по технической ветке?
Говорим о конфликтных ситуациях в команде и о том, как их избежать
$1100*
медианная зарплата в QA в июне 2023

*по результатам опроса QA-инженеров в нашем телеграм-канале

Собеседование

19%*
IT-специалистов переехало или приняло решение о переезде из России по состоянию на конец марта 2022

*по результатам опроса в нашем телеграм-канале

live

Обсуждают сейчас