Что такое параметризованные тесты (Parameterized Tests)?

Ответ

Параметризованные тесты — это методика в модульном тестировании, позволяющая запускать один тестовый метод многократно с разными наборами входных данных и ожидаемых результатов.

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

Реализация в JUnit 5 (Jupiter): Основная аннотация — @ParameterizedTest. Данные предоставляются через источники (@Source).

Примеры источников данных:

  1. @ValueSource: Простые значения.

    @ParameterizedTest
    @ValueSource(strings = {"racecar", "radar", "level"})
    void testPalindromes(String candidate) {
        assertTrue(StringUtils.isPalindrome(candidate));
    }
  2. @CsvSource: Парные "входные-ожидаемые" данные в формате CSV.

    @ParameterizedTest
    @CsvSource({"2, 3, 5", "5, 7, 12"})
    void testAddition(int a, int b, int expectedSum) {
        assertEquals(expectedSum, a + b);
    }
  3. @MethodSource: Данные из статического метода.

    @ParameterizedTest
    @MethodSource("provideStringsForTest")
    void testWithMethodSource(String input, boolean expected) {
        assertEquals(expected, input.length() > 2);
    }
    static Stream<Arguments> provideStringsForTest() {
        return Stream.of(
            Arguments.of("ab", false),
            Arguments.of("abc", true)
        );
    }

Преимущества:

  • Сокращение кода: Нет дублирования тестового метода.
  • Наглядность: Все тестовые случаи видны в одном месте.
  • Легкость расширения: Добавление нового тестового набора — это добавление строки в источник данных.

Недостатки:

  • Отладка: При падении теста нужно определить, для какого именно набора параметров это произошло (JUnit выводит индекс набора).
  • Сложность: Для очень сложных наборов данных подготовка источника может стать нетривиальной.

Ответ 18+ 🔞

А, параметризованные тесты! Ну это ж просто праздник какой-то, блядь! Вместо того чтобы копипастить один и тот же тест как последний мудак, меняя только цифры, можно всё красиво упаковать.

Смотри, суть-то проще пареной репы: один метод, но он гоняется как угорелый с разными входными данными. Как будто ты одного и того же подопытного кролика, блядь, кормишь разной хуйнёй и смотришь — сдохнет или нет.

В JUnit 5 за это отвечает @ParameterizedTest. Аннотация такая, блядь, магическая. Но сам по себе он нихуя не умеет — ему нужна жратва, данные. Это как кричать "Муму!" — а собаки-то нет, блядь.

Откуда данные брать? Да отовсюду, ёпта!

  1. @ValueSource — для простоты, как детская погремушка. Кидаешь в него массивчик значений и всё.

    @ParameterizedTest
    @ValueSource(strings = {"racecar", "radar", "level"})
    void testPalindromes(String candidate) {
        assertTrue(StringUtils.isPalindrome(candidate));
    }

    Вот и проверяются три слова на палиндром. Красота, блядь, а не жизнь.

  2. @CsvSource — вот это уже серьёзнее. Тут можно и вход, и ожидаемый результат в одной строке запихнуть. Как рецепт, сука: две ложки сахара, одна соли — получится говно.

    @ParameterizedTest
    @CsvSource({"2, 3, 5", "5, 7, 12"})
    void testAddition(int a, int b, int expectedSum) {
        assertEquals(expectedSum, a + b);
    }

    Смотри: "2, 3, 5" — это ж целый тестовый сценарий, блядь! Проверили, что 2+3=5. И всё в одной строчке, ёба!

  3. @MethodSource — а это для совсем изощрённых извращенцев. Когда простыми строками не отделаться. Ты пишешь отдельный метод, который эту хуйню генерит.

    @ParameterizedTest
    @MethodSource("provideStringsForTest")
    void testWithMethodSource(String input, boolean expected) {
        assertEquals(expected, input.length() > 2);
    }
    static Stream<Arguments> provideStringsForTest() {
        return Stream.of(
            Arguments.of("ab", false),
            Arguments.of("abc", true)
        );
    }

    Свой собственный конвейер по производству тестовых данных! Хочешь — из базы тяни, хочешь — рандомом генери, хоть с неба лови, блядь.

Чем хороши-то? Да тем, что не нужно плодить десять одинаковых методов, которые отличаются одной циферкой. Добавил строчку в источник — и новый тест готов, в рот меня чих-пых! Всё компактно, всё на виду.

А чем плохи? Ну, во-первых, если тест сломается, JUnit тебе скажет что-то вроде [1] — это индекс упавшего набора. И сиди, гадай, блядь, какой именно это был {"2, 3, 5"} или {"5, 7, 12"}. Не всегда сразу понятно. А во-вторых, если данные надо подготовить — там, файл прочитать, соединение установить — то этот самый MethodSource может превратиться в такого монстра, что мама не горюй.

Но в целом, штука охуенная. Когда нужно проверить кучу граничных значений — это просто спасение, блядь. Главное — не перестараться и не сделать из теста неподъёмную хуйню.