Предисловие
Здравствуйте, я тестировщик Цай Туотуо.
В мире кода существует автоматизированный сад, где варианты использования подобны цветам, развевающимся на ветру и распускающимся разными цветами. В этом саду мы часто сталкиваемся с замечательной ситуацией: один и тот же процесс тестирования, но необходимо переключиться на разные тестовые данные в зависимости от направления бизнеса. Это как музыкальное произведение, одна и та же мелодия, но совершенно разная из-за разных нот.
Как сказал поэт, танцевальные па метода одинаковы, но вносимые ноты разные. Нам нужно подумать об эквивалентных категориях и изучить ценность границ, чтобы составить трогательный тестовый образец.
Однако если вы скопите в метод все тестовые данные, это будет похоже на посев слишком большого количества семян в саду, но он будет выглядеть неорганизованным. Удобство сопровождения и читаемость сценариев использования подобны тусклой дымке, затмевающей их.
В этом поэтическом мире кода поэты всех слоев общества создали сады решений. Точно так же, как у музыкантов есть клавиши и строки, у TestNG есть @Parameters и @DataProvider, а у Pytest также есть музыкальные символы, такие как @pytest.mark.parametrize, которые воспроизводят для нас движение тестирования.
Конечно, Junit также предоставляет нам отличное решение, которое делает написание параметризованных вариантов использования более элегантным. Эта функция позволяет нам красиво запускать один тест несколько раз, используя только разные параметры для каждого запуска. Более того, каждый тестовый пример может существовать независимо, не мешая друг другу.
В этой статье я познакомлю вас с чудесами того, как Junit5 реализует параметризацию. Давайте вместе отправимся в это путешествие и оценим красочные пейзажи мира кода.
Очарование параметризации Junit5 поразительно, а простота ее использования просто поразительна. Просто вставьте несколько аннотаций, чтобы начать путешествие по многомерным данным, и источники данных станут еще более разнообразными: учитываются отдельные параметры, несколько параметров, даже данные в файлах и данные, предоставленные методами. Этот продуманный дизайн обеспечивает беспрецедентную гибкость и богатство тестирования.
Официальная документация: https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests.
Чтобы использовать параметризацию Junit5, вам необходимо импортировать пакет зависимостей junit-jupiter-params на основе платформы Junit.
Если ваш проект построен с использованием Maven, вам нужно только ввести в pom-файл следующие зависимости:
<!-- 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 — это простейший метод параметризации, который позволяет передавать данные или итератор в метод тестирования.
Поддерживается параметризация следующих типов однопараметрических данных:
параметр | параметртип |
---|---|
shorts | short |
bytes | byte |
ints | int |
longs | long |
floats | float |
doubles | double |
chars | char |
booleans | boolean |
strings | java.long.String |
classes | java.long.Class |
@ParameterizedTest
@ValueSource
Для удобства демонстрации,Функция, реализованная с помощью вопроса-алгоритма, будет использоваться в качестве объекта тестирования ниже.,руководитьпараметризменятьвариант использования Практические упражнения:
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:
/**
* @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 передается методу как тестовый параметр,Пример:
@ParameterizedTest
@NullSource
@EmptySource
public void test0(String s) {
assertEquals(0, new DemoTest().lengthOfLongestSubstr(s));
}
Результаты запуска:
@ParameterizedTest
@NullAndEmptySource
public void test1(String s) {
assertEquals(0, new DemoTest().lengthOfLongestSubstr(s));
}
Результаты запуска:
во многих сценариях,Один параметр может быть не идеальным,Часто необходимо передавать одновременнотестданные
иожидаемые результаты
проверитьтест Соответствует ли логика ожиданиям?。с этой целью,Многоэтнический подход будет иметь решающее значение.
Продолжая использовать упомянутую ранее проблему алгоритма, есть следующие два варианта использования:
@ParameterizedTest
// Формат передаваемого параметра представляет собой коллекцию, если параметров несколько, используйте Разделитель. по умолчанию","отдельный
@CsvSource({"abcabcbb,3", "bbbbb,1"})
public void test2(String s, int n) {
assertEquals(n, new DemoTest().lengthOfLongestSubstr(s));
}
Результаты запуска:
Разделитель @CsvSource по умолчанию равен запятой.,на практике,Если запятую необходимо передать в качестве параметра,Затем мы также можем использовать атрибут delimiterString для настройки символа-разделителя.,Пример:
@ParameterizedTest
// использоватьdelimiterStringУкажите разделитель,Используйте значение, чтобы указать источник данных
@CsvSource(value = {"abcabcbb|3", "bbbbb|1"}, delimiterString = "|")
public void test3(String s, int n) {
AssertEquals(n, новый DemoTest().lengthOfLongestSubstr(s));
}
Результаты запуска:
@ParameterizedTest
// Укажите разделительдля“Тест Цай Туотуо”
@CsvSource(value = {"abcabcbbТест Цай Туотуо3", "bbbbbТест Цай Туотуо1"}, delimiterString = "Тест Цай Туотуо")
public void test4(String s, int n) {
assertEquals(n, new DemoTest().lengthOfLongestSubstr(s));
}
Результаты запуска:
При реальном тестировании тестовые данные CSV часто хранятся в файлах CSV, и тестовые данные необходимо получать путем чтения файла.
В настоящее время вы можете использовать аннотацию @CsvFileSource, чтобы указать путь к файлу для чтения источника данных файла.
Обычно аннотация @CsvFileSource анализирует каждую строку, но иногда первая строка может быть именем столбца, поэтому мы можем добавить numLinesToSkip. = 1 атрибут для пропуска строки 1. Также, как и @CsvSource, вы также можете использовать delimiterString для указания. разделитель。
Данные испытаний:
@ParameterizedTest
@CsvFileSource(resources = "/data.csv", numLinesToSkip = 1, delimiterString = "-")
public void test5(String s, int n) {
assertEquals(n, new DemoTest().lengthOfLongestSubstr(s));
}
Результаты запуска:
Происхождение параметра «иметь» — это не просто структура. данных,Документ, хранящийся по параметру, не обязательно является документом CSV.,Или также иметь Excel, YAML и т. д.
затем,Эти сложные структуры данных необходимо преобразовать в тестпараметр.,Нужны умные методы,Преобразуйте его чтение в метод,И передайте метод в качестве параметра тестовому методу.
Junit5 также предлагает замечательное решение.,Мы можем помочь с @MethodSourceаннотация,Передавайте сложные итерируемые объекты в тестовый метод. @MethodSource очень гибок в использовании.,Можно извлечь из документа,Его также можно извлечь из возвращаемого значения интерфейса. после всего,Его суть заключается в использовании метода в качестве источника параметра.,тогда любая сложная структура данных Мы все можем настроить метод.
Если вам нужен только один параметр,Затем вы можете вернуть экземпляр Stream параметра типа.,Пример:
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
)целевой стиль,Примеры следующие:
@ParameterizedTest
@MethodSource("range")
void testWithRangeMethodSource(int argument) {
assertNotEquals(9, argument);
}
static IntStream range() {
return IntStream.range(0, 20).skip(10);
}
Если тестовый метод объявляет несколько параметров,Вам нужно вернуть поток экземпляров коллекции или аргументов.,Как показано ниже:
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. Пусть наше общение будет подобно коду,Постоянно сублимируйте. До свидания.
Вот и все.