Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Какие знаешь основные аннотации 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 4 | JUnit 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
Эти аннотации управляют жизненным циклом тестов и позволяют писать чистый, организованный тестовый код.