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

Можно ли в одном тесте протестировать разный результат метода?

2.0 Middle🔥 181 комментариев
#SOLID и паттерны проектирования

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

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

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

# Тестирование разных результатов в одном тесте

Да, можно и нужно! Есть несколько подходов. Рассмотрю каждый.

1. Параметризованные тесты (best practice)

Используем @ParameterizedTest из JUnit 5. Это самый элегантный способ.

@ValueSource — простые значения

@ParameterizedTest
@ValueSource(ints = {2, 4, 6, 8})
public void testIsEven(int number) {
    assertTrue(NumberUtils.isEven(number));
}

@CsvSource — набор значений

@ParameterizedTest
@CsvSource({
    "2, true",
    "3, false",
    "4, true",
    "5, false"
})
public void testIsEven(int number, boolean expected) {
    assertEquals(expected, NumberUtils.isEven(number));
}

@MethodSource — сложная логика

public class CalculatorTest {
    
    @ParameterizedTest
    @MethodSource("provideDataForAdd")
    public void testAdd(int a, int b, int expected) {
        assertEquals(expected, Calculator.add(a, b));
    }
    
    static Stream<Arguments> provideDataForAdd() {
        return Stream.of(
            Arguments.of(1, 2, 3),
            Arguments.of(-1, 1, 0),
            Arguments.of(0, 0, 0),
            Arguments.of(Integer.MAX_VALUE, 1, Integer.MAX_VALUE + 1)
        );
    }
}

@CsvFileSource — из файла

@ParameterizedTest
@CsvFileSource(resources = "/test-data.csv")
public void testFromFile(String input, String expected) {
    assertEquals(expected, process(input));
}

2. Традиционный подход с циклом

Легче читать, но менее идиоматично:

@Test
public void testMultipleScenarios() {
    int[][] testData = {
        {2, true},
        {3, false},
        {4, true}
    };
    
    for (int[] data : testData) {
        assertEquals(data[1] != 0, NumberUtils.isEven(data[0]));
    }
}

3. Вложенные тесты (@Nested)

Для группировки сценариев:

public class UserServiceTest {
    
    @Nested
    class ValidUserTests {
        @Test
        void testCreateWithValidEmail() { ... }
        
        @Test
        void testCreateWithValidPassword() { ... }
    }
    
    @Nested
    class InvalidUserTests {
        @Test
        void testCreateWithInvalidEmail() { ... }
        
        @Test
        void testCreateWithInvalidPassword() { ... }
    }
}

4. Для мобилов / сложных тестов

Используем TestNG вместо JUnit:

@DataProvider
public Object[][] getTestData() {
    return new Object[][] {
        {1, 2, 3},
        {4, 5, 9},
        {-1, 1, 0}
    };
}

@Test(dataProvider = "getTestData")
public void testAdd(int a, int b, int expected) {
    assertEquals(expected, Calculator.add(a, b));
}

Сравнение подходов

ПодходГибкостьЧитаемостьСкоростьИспользую когда
@ValueSourceнизкаявысокаябыстропростые значения
@CsvSourceсредняявысокаябыстропары вход/выход
@MethodSourceвысокаяхорошаябыстросложные сценарии
Цикл в тестевысокаясредняябыстроlegacy код
@Nestedсредняяочень высокаябыстрогруппировка

Примечания

  1. Когда использовать параметризованные тесты:

    • Много похожих сценариев
    • Разные данные, одна логика
    • Граничные случаи (edge cases)
  2. Когда НЕ использовать:

    • Один уникальный сценарий
    • Каждый случай требует отдельной подготовки
    • Логика сложная и не повторяется
  3. Чтение отчётов:

    testAdd[0] — 1 + 2 = 3  ✓
    testAdd[1] — 4 + 5 = 9  ✓
    testAdd[2] — -1 + 1 = 0 ✓
    

Итог

Да, в JUnit 5 есть отличная поддержка параметризованных тестов. Используй @ParameterizedTest с подходящим источником данных — это делает тесты компактнее, понятнее и проще поддерживать.