官方网站的域名,wordpress图片清理插件下载,做视频比较好的理财网站有哪些,免费域名申请 tkJUnit 5参数化测试
目录
设置我们的第一个参数化测试参数来源 ValueSourceNullSource EmptySourceMethodSourceCsvSourceCsvFileSourceEnumSourceArgumentsSource参数转换参数聚合奖励总结 如果您正在阅读这篇文章#xff0c;说明您已经熟悉了JUnit。让我为您概括一下… JUnit 5参数化测试
目录
设置我们的第一个参数化测试参数来源 ValueSourceNullSource EmptySourceMethodSourceCsvSourceCsvFileSourceEnumSourceArgumentsSource参数转换参数聚合奖励总结 如果您正在阅读这篇文章说明您已经熟悉了JUnit。让我为您概括一下JUnit——在软件开发中我们开发人员编写的代码可能是设计一个人的个人资料这样简单也可能是在银行系统中进行付款这样复杂。在开发这些功能时我们倾向于编写单元测试。顾名思义单元测试的主要目的是确保代码的小、单独部分按预期功能工作。 如果单元测试执行失败这意味着该功能无法按预期工作。编写单元测试的一种工具是JUnit。这些单元测试程序很小但是非常强大并且可以快速执行。现在我们已经了解了JUnit接下来让我们聚焦于JUnit 5中的参数化测试。
参数化测试可以解决在为任何新/旧功能开发测试框架时遇到的最常见问题。
编写针对每个可能输入的测试用例变得更加容易。单个测试用例可以接受多个输入来测试源代码有助于减少代码重复。通过使用多个输入运行单个测试用例我们可以确信已涵盖所有可能的场景并维护更好的代码覆盖率。
开发团队通过利用方法和类来创建可重用且松散耦合的源代码。传递给代码的参数会影响其功能。例如计算器类中的sum方法可以处理整数和浮点数值。JUnit 5引入了执行参数化测试的能力可以使用单个测试用例测试源代码该测试用例可以接受不同的输入。这样可以更有效地进行测试因为在旧版本的JUnit中必须为每种输入类型创建单独的测试用例从而导致大量的代码重复。
示例代码
本文附带有在 GitHub上(code-examples/core-java/junit5-parameterized-tests at master · thombergs/code-examples · GitHub) 的一个可工作的示例代码。
设置
就像疯狂泰坦灭霸喜欢访问力量一样您可以使用以下Maven依赖项来访问JUnit5中参数化测试的力量
dependencygroupIdorg.junit.jupiter/groupIdartifactIdjunit-jupiter-params/artifactIdversion5.9.2/versionscopetest/scope
/dependency
让我们来写些代码好吗
我们的第一个参数化测试
现在我想向您介绍一个新的注解 ParameterizedTest。顾名思义它告诉JUnit引擎使用不同的输入值运行此测试。
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;public class ValueSourceTest {ParameterizedTestValueSource(ints { 2, 4 })void checkEvenNumber(int number) {assertEquals(0, number % 2,Supplied number is not an even number);}
}
在上面的示例中注解ValueSource为 checkEvenNumber() 方法提供了多个输入。假设我们使用JUnit4编写相同的代码即使它们的结果断言完全相同我们也必须编写2个测试用例来覆盖输入2和4。
当我们执行 ValueSourceTest 时我们会看到什么
ValueSourceTest
|_ checkEvenNumber
|_ [1] 2
|_ [2] 4
这意味着 checkEvenNumber() 方法将使用2个输入值执行。
在下一节中让我们学习一下JUnit5框架提供的各种参数来源。
现在我也找了很多测试的朋友做了一个分享技术的交流群共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源没人解答问题坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化性能安全测试开发等等方面有一定建树的技术大牛
分享他们的经验还会分享很多直播讲座和技术沙龙
可以免费学习划重点开源的
qq群号110685036 参数来源
JUnit5提供了许多参数来源注释。下面的章节将简要概述其中一些注释并提供示例。
ValueSource
ValueSource是一个简单的参数源可以接受单个字面值数组。ValueSource支持的字面值类型有short、byte、int、long、float、double、char、boolean、String和Class。
ParameterizedTest
ValueSource(strings { a1, b2 })
void checkAlphanumeric(String word) {assertTrue(StringUtils.isAlphanumeric(word),Supplied word is not alpha-numeric);
}
NullSource EmptySource
假设我们需要验证用户是否已经提供了所有必填字段例如在登录函数中需要提供用户名和密码。我们使用注解来检查提供的字段是否为 null空字符串或空格。
在单元测试中使用 NullSource 和 EmptySource 可以帮助我们提供带有 null、空字符串和空格的数据源并验证源代码的行为。
ParameterizedTest
NullSource
void checkNull(String value) {assertEquals(null, value);
}ParameterizedTest
EmptySource
void checkEmpty(String value) {assertEquals(, value);
}
我们还可以使用 NullAndEmptySource 注解来组合传递 null 和空输入。
ParameterizedTest
NullAndEmptySource
void checkNullAndEmpty(String value) {assertTrue(value null || value.isEmpty());
}
另一个传递 null、空字符串和空格输入值的技巧是结合使用 NullAndEmptySource 注解以覆盖所有可能的负面情况。该注解允许我们从一个或多个测试类的工厂方法中加载输入并生成一个参数流。
ParameterizedTest
NullAndEmptySource
ValueSource(strings { , })
void checkNullEmptyAndBlank(String value) {assertTrue(value null || value.isBlank());
}
MethodSource
该注解允许我们从一个或多个测试类的工厂方法中加载输入并生成一个参数流。
显式方法源 - 测试将尝试加载提供的方法。
// Note: The test will try to load the supplied method
ParameterizedTest
MethodSource(checkExplicitMethodSourceArgs)
void checkExplicitMethodSource(String word) {
assertTrue(StringUtils.isAlphanumeric(word),
Supplied word is not alpha-numeric);
}static StreamString checkExplicitMethodSourceArgs() {
return Stream.of(a1,
b2);
}
隐式方法源 - 测试将搜索与测试类匹配的源方法。
// Note: The test will search for the source method
// that matches the test-case method name
ParameterizedTest
MethodSource
void checkImplicitMethodSource(String word) {assertTrue(StringUtils.isAlphanumeric(word),
Supplied word is not alpha-numeric);
}static StreamString checkImplicitMethodSource() {
return Stream.of(a1,
b2);
}
多参数方法源 - 我们必须将输入作为参数流传递。测试将按照索引顺序加载参数。
// Note: The test will automatically map arguments based on the index
ParameterizedTest
MethodSource
void checkMultiArgumentsMethodSource(int number, String expected) {assertEquals(StringUtils.equals(expected, even) ? 0 : 1, number % 2);
}static StreamArguments checkMultiArgumentsMethodSource() {return Stream.of(Arguments.of(2, even),Arguments.of(3, odd));
}
外部方法源 - 测试将尝试加载外部方法。
// Note: The test will try to load the external method
ParameterizedTest
MethodSource(
source.method.ExternalMethodSource#checkExternalMethodSourceArgs)
void checkExternalMethodSource(String word) {assertTrue(StringUtils.isAlphanumeric(word),
Supplied word is not alpha-numeric);
}
// Note: The test will try to load the external methodParameterizedTestMethodSource(source.method.ExternalMethodSource#checkExternalMethodSourceArgs)void checkExternalMethodSource(String word) { assertTrue(StringUtils.isAlphanumeric(word),Supplied word is not alpha-numeric);}package source.method;
import java.util.stream.Stream;public class ExternalMethodSource {static StreamString checkExternalMethodSourceArgs() {return Stream.of(a1,b2);}
}
CsvSource
该注解允许我们将参数列表作为逗号分隔的值即 CSV 字符串字面量传递每个 CSV 记录都会导致执行一次参数化测试。它还支持使用 useHeadersInDisplayName属性跳过 CSV 标头。
ParameterizedTest
CsvSource({ 2, even,
3, odd})
void checkCsvSource(int number, String expected) {assertEquals(StringUtils.equals(expected, even)? 0 : 1, number % 2);
}
CsvFileSource
该注解允许我们使用类路径或本地文件系统中的逗号分隔值CSV文件。与 CsvSource 类似每个 CSV 记录都会导致执行一次参数化测试。它还支持各种其他属性 -numLinesToSkip、useHeadersInDisplayName、lineSeparator、delimiterString等。
示例 1: 基本实现
ParameterizedTest
CsvFileSource(
files src/test/resources/csv-file-source.csv,
numLinesToSkip 1)
void checkCsvFileSource(int number, String expected) {assertEquals(StringUtils.equals(expected, even)? 0 : 1, number % 2);
}
src/test/resources/csv-file-source.csv
NUMBER, ODD_EVEN
2, even
3, odd
示例2使用属性
ParameterizedTest
CsvFileSource(files src/test/resources/csv-file-source_attributes.csv,delimiterString |,lineSeparator ||,numLinesToSkip 1)
void checkCsvFileSourceAttributes(int number, String expected) {assertEquals(StringUtils.equals(expected, even)
? 0 : 1, number % 2);
}
src/test/resources/csv-file-source_attributes.csv
|| NUMBER | ODD_EVEN ||
|| 2 | even ||
|| 3 | odd ||
EnumSource
该注解提供了一种方便的方法来使用枚举常量作为测试用例参数。支持的属性包括
value - 枚举类类型例如 ChronoUnit.class
package java.time.temporal;public enum ChronoUnit implements TemporalUnit {SECONDS(Seconds, Duration.ofSeconds(1)),MINUTES(Minutes, Duration.ofSeconds(60)),
HOURS(Hours, Duration.ofSeconds(3600)),DAYS(Days, Duration.ofSeconds(86400)),//12 other units
}
ChronoUnit 是一个包含标准日期周期单位的枚举类型。
ParameterizedTest
EnumSource(ChronoUnit.class)
void checkEnumSourceValue(ChronoUnit unit) {
assertNotNull(unit);
}
在此示例中EnumSource 将传递所有16个 ChronoUnit 枚举值作为参数。
names - 枚举常量的名称或选择名称的正则表达式例如 DAYS 或 ^.*DAYS$
ParameterizedTest
EnumSource(names { DAYS, HOURS })
void checkEnumSourceNames(ChronoUnit unit) {assertNotNull(unit);
}
ArgumentsSource
该注解提供了一个自定义的可重用ArgumentsProvider。ArgumentsProvider的实现必须是外部类或静态嵌套类。
外部参数提供程序
public class ArgumentsSourceTest {ParameterizedTestArgumentsSource(ExternalArgumentsProvider.class)void checkExternalArgumentsSource(int number, String expected) {assertEquals(StringUtils.equals(expected, even)? 0 : 1, number % 2,Supplied number number is not an expected number);}
}public class ExternalArgumentsProvider implements ArgumentsProvider {Overridepublic Stream? extends Arguments provideArguments(ExtensionContext context) throws Exception {return Stream.of(Arguments.of(2, even),Arguments.of(3, odd));}
}
静态嵌套参数提供程序
public class ArgumentsSourceTest {ParameterizedTestArgumentsSource(NestedArgumentsProvider.class)void checkNestedArgumentsSource(int number, String expected) {assertEquals(StringUtils.equals(expected, even)
? 0 : 1, number % 2,Supplied number number is not an expected number);}static class NestedArgumentsProvider implements ArgumentsProvider {Overridepublic Stream? extends Arguments provideArguments(ExtensionContext context) throws Exception {return Stream.of(Arguments.of(2, even),Arguments.of(3, odd));}}
}
参数转换
首先想象一下如果没有参数转换我们将不得不自己处理参数数据类型的问题。
源方法 Calculator 类
public int sum(int a, int b) {return a b;
}
测试用例
ParameterizedTest
CsvSource({ 10, 5, 15 })
void calculateSum(String num1, String num2, String expected) {int actual calculator.sum(Integer.parseInt(num1),Integer.parseInt(num2));assertEquals(Integer.parseInt(expected), actual);
}
如果我们有String参数而我们正在测试的源方法接受Integers则在调用源方法之前我们需要负责进行此转换。
JUnit5 提供了不同的参数转换方式
扩展原始类型转换
ParameterizedTest
ValueSource(ints { 2, 4 })
void checkWideningArgumentConversion(long number) {assertEquals(0, number % 2);
}
使用 ValueSource(ints { 1, 2, 3 }) 进行参数化测试时可以声明接受 int、long、float 或 double 类型的参数。
隐式转换
ParameterizedTest
ValueSource(strings DAYS)
void checkImplicitArgumentConversion(ChronoUnit argument) {assertNotNull(argument.name());
}
JUnit5提供了几个内置的隐式类型转换器。转换取决于声明的方法参数类型。例如用ValueSource(strings DAYS)注释的参数化测试会隐式转换为类型ChronoUnit的参数。
回退字符串到对象的转换
ParameterizedTest
ValueSource(strings { Name1, Name2 })
void checkImplicitFallbackArgumentConversion(Person person) {assertNotNull(person.getName());
}public class Person {private String name;public Person(String name) {this.name name;}//Getters Setters
}
JUnit5提供了一个回退机制用于自动将字符串转换为给定目标类型如果目标类型声明了一个适用的工厂方法或工厂构造函数。例如用ValueSource(strings { Name1, Name2 })注释的参数化测试可以声明接受一个类型为Person的参数其中包含一个名为name且类型为string的单个字段。
显式转换
ParameterizedTest
ValueSource(ints { 100 })
void checkExplicitArgumentConversion(ConvertWith(StringSimpleArgumentConverter.class) String argument) {assertEquals(100, argument);
}public class StringSimpleArgumentConverter extends SimpleArgumentConverter {Overrideprotected Object convert(Object source, Class? targetType)throws ArgumentConversionException {return String.valueOf(source);}
}
如果由于某种原因您不想使用隐式参数转换则可以使用ConvertWith注释来定义自己的参数转换器。例如用ValueSource(ints { 100 })注释的参数化测试可以声明接受一个类型为String的参数使用 StringSimpleArgumentConverter.class将整数转换为字符串类型。
参数聚合
ArgumentsAccessor
默认情况下提供给ParameterizedTest方法的每个参数对应于一个方法参数。因此当提供大量参数的参数源可以导致大型方法签名时我们可以使用ArgumentsAccessor而不是声明多个参数。类型转换支持如上面的隐式转换所述。
ParameterizedTest
CsvSource({ John, 20,Harry, 30 })
void checkArgumentsAccessor(ArgumentsAccessor arguments) {Person person new Person(arguments.getString(0),arguments.getInteger(1));assertTrue(person.getAge() 19, person.getName() is a teenager);
}
自定义聚合器
我们看到ArgumentsAccessor可以直接访问ParameterizedTest方法的参数。如果我们想在多个测试中声明相同的ArgumentsAccessor怎么办JUnit5通过提供自定义可重用的聚合器来解决此问题。
AggregateWith
ParameterizedTest
CsvSource({ John, 20,Harry, 30 })
void checkArgumentsAggregator(AggregateWith(PersonArgumentsAggregator.class) Person person) {assertTrue(person.getAge() 19, person.getName() is a teenager);
}public class PersonArgumentsAggregator implements ArgumentsAggregator {Overridepublic Object aggregateArguments(ArgumentsAccessor arguments,ParameterContext context) throws ArgumentsAggregationException {return new Person(arguments.getString(0),
arguments.getInteger(1));}
}
实现ArgumentsAggregator接口并通过AggregateWith注释在ParameterizedTest方法中注册它。当我们执行测试时它会将聚合结果作为对应测试的参数提供。ArgumentsAggregator的实现可以是外部类或静态嵌套类。
额外福利
由于您已经阅读完文章我想给您一个额外的福利 - 如果您正在使用像Fluent assertions for javaAssertJ - fluent assertions java library这样的断言框架则可以将 java.util.function.Consumer作为参数传递其中包含断言本身。
ParameterizedTest
MethodSource(checkNumberArgs)
void checkNumber(int number, ConsumerInteger consumer) {consumer.accept(number);
}static StreamArguments checkNumberArgs() { ConsumerInteger evenConsumer i - Assertions.assertThat(i % 2).isZero();ConsumerInteger oddConsumer i - Assertions.assertThat(i % 2).isEqualTo(1);return Stream.of(Arguments.of(2, evenConsumer),Arguments.of(3, oddConsumer));
}
总结
JUnit5的参数化测试功能通过消除重复测试用例的需要提供多次使用不同输入运行相同测试的能力实现了高效的测试。这不仅为开发团队节省了时间和精力而且还增加了测试过程的覆盖范围和有效性。此外该功能允许对源代码进行更全面的测试因为可以使用更广泛的输入进行测试从而增加了识别任何潜在的错误或问题的机会。总体而言JUnit5的参数化测试是提高代码质量和可靠性的有价值的工具。 最后感谢每一个认真阅读我文章的人看着粉丝一路的上涨和关注礼尚往来总是要有的虽然不是什么很值钱的东西如果你用得到的话可以直接拿走 软件测试面试文档
我们学习必然是为了找到高薪的工作下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料并且有字节大佬给出了权威的解答刷完这一套面试资料相信大家都能找到满意的工作。