Практика параметризации Junit5 делает тестирование более элегантным
Практика параметризации Junit5 делает тестирование более элегантным

Предисловие

Здравствуйте, я тестировщик Цай Туотуо.

В мире кода существует автоматизированный сад, где варианты использования подобны цветам, развевающимся на ветру и распускающимся разными цветами. В этом саду мы часто сталкиваемся с замечательной ситуацией: один и тот же процесс тестирования, но необходимо переключиться на разные тестовые данные в зависимости от направления бизнеса. Это как музыкальное произведение, одна и та же мелодия, но совершенно разная из-за разных нот.

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

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

В этом поэтическом мире кода поэты всех слоев общества создали сады решений. Точно так же, как у музыкантов есть клавиши и строки, у TestNG есть @Parameters и @DataProvider, а у Pytest также есть музыкальные символы, такие как @pytest.mark.parametrize, которые воспроизводят для нас движение тестирования.

Конечно, Junit также предоставляет нам отличное решение, которое делает написание параметризованных вариантов использования более элегантным. Эта функция позволяет нам красиво запускать один тест несколько раз, используя только разные параметры для каждого запуска. Более того, каждый тестовый пример может существовать независимо, не мешая друг другу.

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

Параметризация Junit5

Очарование параметризации Junit5 поразительно, а простота ее использования просто поразительна. Просто вставьте несколько аннотаций, чтобы начать путешествие по многомерным данным, и источники данных станут еще более разнообразными: учитываются отдельные параметры, несколько параметров, даже данные в файлах и данные, предоставленные методами. Этот продуманный дизайн обеспечивает беспрецедентную гибкость и богатство тестирования.

Официальная документация: https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests.

Установить зависимости

Чтобы использовать параметризацию Junit5, вам необходимо импортировать пакет зависимостей junit-jupiter-params на основе платформы Junit.

Если ваш проект построен с использованием Maven, вам нужно только ввести в pom-файл следующие зависимости:

Язык кода:javascript
копировать
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>
Один параметр @ValueSource

@ValueSource — это простейший метод параметризации, который позволяет передавать данные или итератор в метод тестирования.

Поддерживается параметризация следующих типов однопараметрических данных:

параметр

параметртип

shorts

short

bytes

byte

ints

int

longs

long

floats

float

doubles

double

chars

char

booleans

boolean

strings

java.long.String

classes

java.long.Class

Этапы использования
  • При использовании параметризованных вариантов использования,Нужно@Testаннотация Заменить на@ParameterizedTest
  • Добавить заказпараметризменятьаннотация@ValueSource
  • Примечание: Если @Testи@ParameterizedTest используется одновременно,будет выполнен еще раз,И поскольку @Test не может передать параметр,Таким образом, об исключении ParameterResolutionException будет сообщено во время выполнения.
Практические упражнения

Для удобства демонстрации,Функция, реализованная с помощью вопроса-алгоритма, будет использоваться в качестве объекта тестирования ниже.,руководитьпараметризменятьвариант использования Практические упражнения:

Язык кода:javascript
копировать
package top.caituotuo.demo;

import java.util.HashMap;
import java.util.Map;

/**
 * author: Тест Цай Туотуо
 * datetime: 2023-8-21 02:12:43
 * function: В данной строке найдите длину самой длинной подстроки, не содержащей повторяющихся символов.
 * Например:
 * Учитывая «abcabcbb», самая длинная подстрока без повторяющихся символов — это «abc» длиной 3.
 * Данный "bbbbb" , самая длинная подстрока "b" , длина 1。
 * Данный "pwwkew" , самая длинная подстрока "wke" , длина 3。
 * Обратите внимание, что ответом должна быть подстрока «pwke». является подпоследовательностью вместо подстроки.
 */

public class DemoTest {
    public int lengthOfLongestSubstr(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }
        // Определите значение массива dp: если заканчивается символом s[i], длина неповторяющейся подстроки равна dp[i]
        int[] dp = new int[s.length()];
        // начальное значение
        dp[0] = 1;
        Map<Character, Integer> map = new HashMap<>();
        map.put(s.charAt(0), 0);
        int maxLen = 1;
        int startIndex = 0;
        // отношения перехода состояния
        for (int i = 1; i < s.length(); i++) {
            if (!map.containsKey(s.charAt(i))) {
                dp[i] = dp[i - 1] + 1;
            } else {
                int k = map.get(s.charAt(i));
                dp[i] = i - k <= dp[i - 1] ? i - k : dp[i - 1] + 1;
            }
            // maxLen = Math.max(maxLen, dp[i]);
            if (dp[i] > maxLen) {
                maxLen = dp[i];
                startIndex = i - maxLen + 1;
            }
            map.put(s.charAt(i), i);
        }
        System.out.printf("Исходная строка: %s, самая длинная неповторяющаяся подстрока: %s, длина: %s%n", s, s.substring(startIndex, startIndex + maxLen), maxLen);
        return maxLen;
    }
}

Преобразуйте строку в одну строку типа String:

Язык кода:javascript
копировать
/**
 * @param s Формальный параметр объявляется в тестовом методе, что означает, что параметр передается тестовому методу для использования через этот формальный параметр.
 */
// @Test
// Воля@TestannotationСяочэн@ParameterizedTestannotation,указатьparameterizedизменятьtestиспользовать вещи
@ParameterizedTest
// Одинарная параметрнотация, в примере это параметр типа String.
@ValueSource(strings = {"abcabcbb", "pwwkew"})
public void test(String s) {
    assertEquals(3, new DemoTest().lengthOfLongestSubstr(s));
}

Результаты запуска:

Начиная с Junit5.4, вы можете использовать аннотации @NullSource, @EmptySource и @NullAndEmptySource для преобразования одного значения NULL и одного значения Empty соответственно. и null+Empty передается методу как тестовый параметр,Пример:

Язык кода:javascript
копировать
@ParameterizedTest
@NullSource
@EmptySource
public void test0(String s) {
    assertEquals(0, new DemoTest().lengthOfLongestSubstr(s));
}

Результаты запуска:

Язык кода:javascript
копировать
@ParameterizedTest
@NullAndEmptySource
public void test1(String s) {
    assertEquals(0, new DemoTest().lengthOfLongestSubstr(s));
}

Результаты запуска:

Многопараметрический @CsvSource

во многих сценариях,Один параметр может быть не идеальным,Часто необходимо передавать одновременнотестданныеиожидаемые результатыпроверитьтест Соответствует ли логика ожиданиям?。с этой целью,Многоэтнический подход будет иметь решающее значение.

Продолжая использовать упомянутую ранее проблему алгоритма, есть следующие два варианта использования:

  1. Учитывая «abcabcbb», самая длинная подстрока без повторяющихся символов — это «abc» длиной 3.
  2. Учитывая «bbbbb», самая длинная подстрока без повторяющихся символов — это «b» длиной 1.
Этапы использования
  • добавить большепараметрпараметризменятьаннотация @CsvSource
  • @CsvSource параметризация по умолчанию или указанный разделитель
Практические упражнения
Разделитель по умолчанию
Язык кода:javascript
копировать
@ParameterizedTest
// Формат передаваемого параметра представляет собой коллекцию, если параметров несколько, используйте Разделитель. по умолчанию","отдельный
@CsvSource({"abcabcbb,3", "bbbbb,1"})
public void test2(String s, int n) {
    assertEquals(n, new DemoTest().lengthOfLongestSubstr(s));
}

Результаты запуска:

Укажите разделитель

Разделитель @CsvSource по умолчанию равен запятой.,на практике,Если запятую необходимо передать в качестве параметра,Затем мы также можем использовать атрибут delimiterString для настройки символа-разделителя.,Пример:

Язык кода:javascript
копировать
@ParameterizedTest
// использоватьdelimiterStringУкажите разделитель,Используйте значение, чтобы указать источник данных
@CsvSource(value = {"abcabcbb|3", "bbbbb|1"}, delimiterString = "|")
public void test3(String s, int n) {
    AssertEquals(n, новый DemoTest().lengthOfLongestSubstr(s));
}

Результаты запуска:

Язык кода:javascript
копировать
@ParameterizedTest
// Укажите разделительдля“Тест Цай Туотуо”
@CsvSource(value = {"abcabcbbТест Цай Туотуо3", "bbbbbТест Цай Туотуо1"}, delimiterString = "Тест Цай Туотуо")
public void test4(String s, int n) {
    assertEquals(n, new DemoTest().lengthOfLongestSubstr(s));
}

Результаты запуска:

Многопараметрическая параметризация файла @CsvFileSource

При реальном тестировании тестовые данные CSV часто хранятся в файлах CSV, и тестовые данные необходимо получать путем чтения файла.

В настоящее время вы можете использовать аннотацию @CsvFileSource, чтобы указать путь к файлу для чтения источника данных файла.

Этапы использования
  • добавить большепараметрдокументпараметризменятьаннотация @CsvFileSource
  • в проекте test/resources Добавлены тестданные в csv документ
  • Поддержка @CsvFileSource Укажите параметр-разделитель.
Практические упражнения

Обычно аннотация @CsvFileSource анализирует каждую строку, но иногда первая строка может быть именем столбца, поэтому мы можем добавить numLinesToSkip. = 1 атрибут для пропуска строки 1. Также, как и @CsvSource, вы также можете использовать delimiterString для указания. разделитель。

Данные испытаний:

Язык кода:javascript
копировать
@ParameterizedTest
@CsvFileSource(resources = "/data.csv", numLinesToSkip = 1, delimiterString = "-")
public void test5(String s, int n) {
    assertEquals(n, new DemoTest().lengthOfLongestSubstr(s));
}

Результаты запуска:

Параметры метода @MethodSource

Происхождение параметра «иметь» — это не просто структура. данных,Документ, хранящийся по параметру, не обязательно является документом CSV.,Или также иметь Excel, YAML и т. д.

затем,Эти сложные структуры данных необходимо преобразовать в тестпараметр.,Нужны умные методы,Преобразуйте его чтение в метод,И передайте метод в качестве параметра тестовому методу.

Junit5 также предлагает замечательное решение.,Мы можем помочь с @MethodSourceаннотация,Передавайте сложные итерируемые объекты в тестовый метод. @MethodSource очень гибок в использовании.,Можно извлечь из документа,Его также можно извлечь из возвращаемого значения интерфейса. после всего,Его суть заключается в использовании метода в качестве источника параметра.,тогда любая сложная структура данных Мы все можем настроить метод.

Этапы использования
  • Эталонный метод как информация об источнике данных параметра от @MethodSourceаннотация,Позволяет ссылаться на фабричные методы одного или нескольких тестовых классов.,Такой метод должен возвращать Stream,Iterable,Итератор или массив параметров. кроме того,Этот метод не может принимать какие-либо параметры.
  • Параметр в @MethodSourceаннотация должен быть статическим фабричным методом, если тестовый класс не аннотирован @TestInstance(Lifecycle.PER_CLASS).
  • Возвращаемое значение статического фабричного метода нуждается в параметре, соответствующем методу итест.
  • Если имя метода не указано в @MethodSourceаннотация,Статический метод с тем же именем, что и тестовый метод, будет вызван автоматически.
Практические упражнения

Если вам нужен только один параметр,Затем вы можете вернуть экземпляр Stream параметра типа.,Пример:

Язык кода:javascript
копировать
package top.caituotuo.demo;

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

import java.util.stream.Stream;

/**
 * author: Тест Цай Туотуо
 * datetime: 2023/8/26 16:38
 * function: Метод одного параметра
 */
public class MethodSourceTest {
    /**
     * @param name Добавьте формальные параметры. Тип формального параметра должен соответствовать типу элемента внутри статического метода.
     */
    @ParameterizedTest
    // Укажите имя метода источника данных через @MethodSourceаннотация.
    @MethodSource("stringProvider")
    void test1(String name) {
        System.out.println(name);
    }

    /**
     * Определите статический метод, который предоставляет источник данных.
     *
     * @return Обратный поток
     */
    static Stream<String> stringProvider() {
        return Stream.of("Тест Цай Туотуо", «Сяо Па Цай», «Ученик начальной школы ИТ Цай Туотуо»);
    }
}

Результаты запуска:

Поддержка оригиналатип(DoubleStream,IntStreamиLongStream)целевой стиль,Примеры следующие:

Язык кода:javascript
копировать
@ParameterizedTest
@MethodSource("range")
void testWithRangeMethodSource(int argument) {
    assertNotEquals(9, argument);
}
static IntStream range() {
    return IntStream.range(0, 20).skip(10);
}

Если тестовый метод объявляет несколько параметров,Вам нужно вернуть поток экземпляров коллекции или аргументов.,Как показано ниже:

Язык кода:javascript
копировать
package top.caituotuo.demo;

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

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

/**
 * author: Тест Цай Туотуо
 * datetime: 2023/8/22 23:32
 * function: Учитывая список из трех чисел, определите, могут ли эти три числа образовать треугольник. Если это возможно, он выведет true, если нет, то выведет false.
 * Введите [3,4,3] вывод true
 * Введите [1,2,3] вывести ложь
 */
public class DemoTest {
    public boolean isTriangle(List<Integer> sides) {
        if (sides.size() != 3) {
            return false;
        }

        return sides.stream().allMatch(side -> side > 0) &&
                IntStream.range(0, 3).allMatch(i ->
                        sides.get(i) + sides.get((i + 1) % 3) > sides.get((i + 2) % 3));
    }

    @ParameterizedTest
    @MethodSource({"getTestSides"})
    public void test(List<Integer> sides, boolean expectedResult) {
        assertEquals(expectedResult, new DemoTest().isTriangle(sides));
    }

    static Stream<Arguments> getTestSides() {
        return Stream.of(
                Arguments.of(Arrays.asList(3, 4, 3), true),
                Arguments.of(Arrays.asList(1, 2, 3), false),
                Arguments.of(Arrays.asList(-3, 4, 5), false),
                Arguments.of(Arrays.asList(3, 4, 5, 6), false)
        );
    }
}

Результаты запуска:

о Параметризация Обсуждение Junit5,Давайте пока прекратим здесь разговоры,Мы встретимся снова в следующем выпуске. С нетерпением жду возможности снова поделиться с вами духовным путешествием Elegant. Пусть наше общение будет подобно коду,Постоянно сублимируйте. До свидания.

Вот и все.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose