← Назад к вопросам

Какие знаешь основные аннотации JUnit?

1.6 Junior🔥 301 комментариев
#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Какие знаешь основные аннотации JUnit?

JUnit — это популярный фреймворк для модульного тестирования в Java. Аннотации JUnit определяют жизненный цикл и поведение тестов. Рассмотрю основные аннотации JUnit 4 и JUnit 5.

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

@Test

Обозначает метод как test case.

import org.junit.Test;
import static org.junit.Assert.*;

public class CalculatorTest {
    
    @Test
    public void testAddition() {
        int result = 2 + 2;
        assertEquals(4, result);
    }
    
    @Test
    public void testDivision() {
        double result = 10.0 / 2.0;
        assertEquals(5.0, result, 0.01);
    }
}

Характеристики:

  • Должен быть public void метод
  • Может иметь timeout
  • Может ожидать исключение

С ожиданием исключения:

@Test(expected = ArithmeticException.class)
public void testDivisionByZero() {
    int result = 10 / 0;  // Должно выбросить исключение
}

@Test(timeout = 1000)
public void testTimeout() {
    // Тест должен завершиться за 1 секунду
    slowOperation();
}

@Before

Выполняется перед КАЖДЫМ тестом.

public class UserServiceTest {
    
    private UserService service;
    private UserRepository repository;
    
    @Before
    public void setUp() {  // Выполняется перед каждым @Test
        repository = new MockUserRepository();
        service = new UserService(repository);
    }
    
    @Test
    public void testCreateUser() {
        // service готов к использованию
    }
    
    @Test
    public void testFindUser() {
        // service еще раз инициализирован для этого теста
    }
}

Порядок вызова:

1. @Before (setUp)
2. @Test (testCreateUser)
3. @After (tearDown)
4. @Before (setUp)  ← Снова!
5. @Test (testFindUser)
6. @After (tearDown)

@After

Выполняется ПОСЛЕ КАЖДОГО теста.

public class DatabaseTest {
    
    private Connection connection;
    
    @Before
    public void setUp() throws SQLException {
        connection = DriverManager.getConnection("jdbc:sqlite::memory:");
    }
    
    @After
    public void tearDown() throws SQLException {
        if (connection != null) {
            connection.close();  // Закрытие ресурсов
        }
    }
    
    @Test
    public void testQuery() throws SQLException {
        // connection готов
        Statement stmt = connection.createStatement();
        // ...
    }
}

@BeforeClass

Выполняется ОДИН раз перед всеми тестами (static метод).

public class ExpensiveSetupTest {
    
    private static DatabasePool pool;
    
    @BeforeClass
    public static void setUpClass() {  // static!
        // Выполняется один раз, перед всеми тестами
        pool = new DatabasePool(10);  // Создаем пул один раз
    }
    
    @Test
    public void testQuery1() {
        // pool уже инициализирован
    }
    
    @Test
    public void testQuery2() {
        // Используем тот же pool
    }
}

Когда использовать:

  • Инициализация дорогостоящих ресурсов (database, server)
  • Создание статических данных
  • Загрузка конфигурации

@AfterClass

Выполняется ОДИН раз после всех тестов (static метод).

public class ServerTest {
    
    private static MockServer server;
    
    @BeforeClass
    public static void setUpClass() {
        server = new MockServer(8080);
        server.start();
    }
    
    @AfterClass
    public static void tearDownClass() {
        // Выполняется один раз в конце
        server.stop();  // Выключаем сервер после всех тестов
    }
    
    @Test
    public void testEndpoint1() {
        // Используем server
    }
    
    @Test
    public void testEndpoint2() {
        // Используем тот же server
    }
}

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

JUnit 5 имеет другое имена и улучшения:

@Test (JUnit 5)

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

public class CalculatorTest {
    
    @Test
    public void testAddition() {
        assertEquals(4, 2 + 2);
    }
}

@BeforeEach (вместо @Before)

import org.junit.jupiter.api.BeforeEach;

public class UserServiceTest {
    
    private UserService service;
    
    @BeforeEach  // Вместо @Before
    void setUp() {
        service = new UserService();
    }
    
    @Test
    void testCreateUser() {
        // ...
    }
}

@AfterEach (вместо @After)

import org.junit.jupiter.api.AfterEach;

public class FileTest {
    
    private FileWriter writer;
    
    @BeforeEach
    void setUp() {
        writer = new FileWriter("test.txt");
    }
    
    @AfterEach
    void tearDown() throws IOException {
        if (writer != null) {
            writer.close();
        }
    }
    
    @Test
    void testWrite() throws IOException {
        writer.write("test");
    }
}

@BeforeAll (вместо @BeforeClass)

import org.junit.jupiter.api.BeforeAll;

public class TestSuite {
    
    private static DatabaseConnection db;
    
    @BeforeAll
    static void setUpAll() {  // static!
        db = new DatabaseConnection("production_db");
        db.connect();
    }
    
    @Test
    void test1() {
        // Используем db
    }
}

@AfterAll (вместо @AfterClass)

import org.junit.jupiter.api.AfterAll;

public class TestSuite {
    
    private static DatabaseConnection db;
    
    @AfterAll
    static void tearDownAll() {  // static!
        db.disconnect();
        db = null;
    }
}

Дополнительные аннотации JUnit

@Ignore (JUnit 4) / @Disabled (JUnit 5)

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

// JUnit 4
@Ignore("Нетривиальное поведение, нужно отладить")
@Test
public void testComplexFeature() {
    // Этот тест не будет выполняться
}

// JUnit 5
@Disabled("Ждем исправления бага JIRA-123")
@Test
void testBuggyFeature() {
    // Пропускается
}

@RunWith (JUnit 4)

Задает параметризованный запуск тестов.

import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class ParametrizedTest {
    
    private int input;
    private int expected;
    
    public ParametrizedTest(int input, int expected) {
        this.input = input;
        this.expected = expected;
    }
    
    @Parameterized.Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
            { 1, 2 },
            { 2, 4 },
            { 3, 6 }
        });
    }
    
    @Test
    public void testDoubling() {
        assertEquals(expected, input * 2);
    }
}

@ParameterizedTest (JUnit 5)

Обновленная версия параметризованного тестирования.

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class ParametrizedTestJUnit5 {
    
    @ParameterizedTest
    @ValueSource(ints = { 1, 2, 3, 4, 5 })
    void testWithInts(int value) {
        assertTrue(value > 0);
    }
    
    @ParameterizedTest
    @ValueSource(strings = { "apple", "banana", "cherry" })
    void testWithStrings(String value) {
        assertFalse(value.isEmpty());
    }
    
    @ParameterizedTest
    @CsvSource({
        "1, 1, 2",
        "2, 3, 5",
        "3, 4, 7"
    })
    void testAddition(int a, int b, int expected) {
        assertEquals(expected, a + b);
    }
}

@DisplayName (JUnit 5)

Читаемое имя теста.

public class DisplayNameTest {
    
    @Test
    @DisplayName("Проверка сложения двух положительных чисел")
    void testAddPositive() {
        assertEquals(5, 2 + 3);
    }
    
    @Test
    @DisplayName("Обработка отрицательных чисел ✓")
    void testNegativeNumbers() {
        assertEquals(-1, 2 + (-3));
    }
}

Выводит в отчет:

✓ Проверка сложения двух положительных чисел
✓ Обработка отрицательных чисел ✓

@Nested (JUnit 5)

Укладывает тесты в подклассы для организации.

public class CalculatorTest {
    
    @Nested
    @DisplayName("Тесты сложения")
    class AdditionTests {
        
        @Test
        @DisplayName("Позитивное число + позитивное число")
        void testPositivePlusPositive() {
            assertEquals(5, 2 + 3);
        }
    }
    
    @Nested
    @DisplayName("Тесты вычитания")
    class SubtractionTests {
        
        @Test
        @DisplayName("Позитивное число - позитивное число")
        void testPositiveMinusPositive() {
            assertEquals(1, 3 - 2);
        }
    }
}

Жизненный цикл теста (JUnit 5)

public class LifecycleTest {
    
    @BeforeAll
    static void setUpAll() {
        System.out.println("1. @BeforeAll - один раз перед ВСЕМИ тестами");
    }
    
    @BeforeEach
    void setUp() {
        System.out.println("2. @BeforeEach - перед КАЖДЫМ тестом");
    }
    
    @Test
    @DisplayName("Первый тест")
    void test1() {
        System.out.println("3. Выполнение TEST 1");
    }
    
    @Test
    @DisplayName("Второй тест")
    void test2() {
        System.out.println("3. Выполнение TEST 2");
    }
    
    @AfterEach
    void tearDown() {
        System.out.println("4. @AfterEach - после КАЖДОГО теста");
    }
    
    @AfterAll
    static void tearDownAll() {
        System.out.println("5. @AfterAll - один раз после ВСЕХ тестов");
    }
}

// Вывод:
// 1. @BeforeAll
// 2. @BeforeEach
// 3. Выполнение TEST 1
// 4. @AfterEach
// 2. @BeforeEach
// 3. Выполнение TEST 2
// 4. @AfterEach
// 5. @AfterAll

Таблица сравнения JUnit 4 и JUnit 5

НазначениеJUnit 4JUnit 5
Основной тест@Test@Test
До каждого@Before@BeforeEach
После каждого@After@AfterEach
До всех@BeforeClass@BeforeAll
После всех@AfterClass@AfterAll
Пропустить@Ignore@Disabled
Параметризация@RunWith@ParameterizedTest
Вложенность-@Nested
Отображение-@DisplayName

Assertions (Проверки)

JUnit 4

import static org.junit.Assert.*;

@Test
public void testAssertions() {
    assertEquals(4, 2 + 2);           // Равенство
    assertNotEquals(4, 2 + 3);        // Неравенство
    assertTrue(2 > 1);                 // Правда
    assertFalse(2 < 1);                // Ложь
    assertNull(null);                  // Null
    assertNotNull("test");             // Не null
    assertSame(obj1, obj1);            // Один и тот же объект
    assertArrayEquals(arr1, arr2);     // Массивы равны
    assertThat(value, is(5));          // Matcher
}

JUnit 5

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

@Test
public void testAssertions() {
    assertEquals(4, 2 + 2);
    assertNotEquals(4, 2 + 3);
    assertTrue(2 > 1);
    assertFalse(2 < 1);
    assertNull(null);
    assertNotNull("test");
    assertSame(obj1, obj1);
    assertThrows(ArithmeticException.class, () -> 10 / 0);
    assertDoesNotThrow(() -> Integer.parseInt("5"));
    assertAll("assertions",
        () -> assertEquals(4, 2 + 2),
        () -> assertTrue(true)
    );
}

Best Practices

1. Используй @BeforeEach для инициализации

// ✅ Хорошо
public class ServiceTest {
    
    private Service service;
    
    @BeforeEach
    void setUp() {
        service = new Service();  // Новый экземпляр для каждого теста
    }
}

// ❌ Плохо (тесты влияют друг на друга)
public class BadTest {
    private static Service service = new Service();
}

2. Используй @DisplayName для понятных описаний

// ✅ Хорошо
@Test
@DisplayName("Проверка поиска пользователя по ID")
void findUserById() { }

// ❌ Плохо
@Test
void test1() { }

3. Избегай @BeforeClass для не-статических ресурсов

// ✅ Правильно
@BeforeAll
static void setupExpensiveResource() {
    // Статический метод для shared ресурсов
}

// ❌ Неправильно
@Before
void setupExpensiveResource() {
    // Это выполняется перед КАЖДЫМ тестом
}

Заключение

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

JUnit 4:

  • @Test, @Before, @After
  • @BeforeClass, @AfterClass
  • @Ignore для пропуска

JUnit 5:

  • @Test, @BeforeEach, @AfterEach
  • @BeforeAll, @AfterAll
  • @Disabled, @DisplayName
  • @ParameterizedTest, @Nested

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