发布于2021-03-10 18:23 阅读(1361) 评论(0) 点赞(8) 收藏(0)
https://github.com/zq2599/blog_demos
内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;
《JUnit5学习》系列旨在通过实战提升SpringBoot环境下的单元测试技能,一共八篇文章,链接如下:
名称 | 链接 | 备注 |
---|---|---|
项目主页 | https://github.com/zq2599/blog_demos | 该项目在GitHub上的主页 |
git仓库地址(https) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https协议 |
git仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh协议 |
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
3. 除了用@DisplayName指定展示名称,JUnit5还提供了一种自动生成展示名称的功能:@DisplayNameGeneration,来看看它是如何生成展示名称的;
4. 演示代码如下所示,当@DisplayNameGeneration的value设置为ReplaceUnderscores时,会把方法名的所有下划线替换为空格:
package com.bolingcavalry.advanced.service.impl;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
public class ReplaceUnderscoresTest {
@Test
void if_it_is_zero() {
}
}
6. 在上述替换方式的基础上,JUnit5还提供了另一种生成展示名称的方法:测试类名+连接符+测试方法名,并且类名和方法名的下划线都会被替换成空格,演示代码如下,使用了注解@IndicativeSentencesGeneration,其separator属性就是类名和方法名之间的连接符:
package com.bolingcavalry.advanced.service.impl;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.IndicativeSentencesGeneration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@IndicativeSentencesGeneration(separator = ",测试方法:", generator = DisplayNameGenerator.ReplaceUnderscores.class)
public class IndicativeSentences_Test {
@Test
void if_it_is_one_of_the_following_years() {
}
}
@Order(1)
@DisplayName("重复测试")
@RepeatedTest(5)
void repeatTest(TestInfo testInfo) {
log.info("测试方法 [{}]", testInfo.getTestMethod().get().getName());
}
3. 在测试方法执行时,如果想了解当前是第几次执行,以及总共有多少次,只要给测试方法增加RepetitionInfo类型的入参即可,演示代码如下,可见RepetitionInfo提供的API可以得到总数和当前次数:
@Order(2)
@DisplayName("重复测试,从入参获取执行情况")
@RepeatedTest(5)
void repeatWithParamTest(TestInfo testInfo, RepetitionInfo repetitionInfo) {
log.info("测试方法 [{}],当前第[{}]次,共[{}]次",
testInfo.getTestMethod().get().getName(),
repetitionInfo.getCurrentRepetition(),
repetitionInfo.getTotalRepetitions());
}
5. 在上图的左下角可见,重复执行的结果被展示为"repetition X of X"这样的内容,其实这部分信息是可以定制的,就是RepeatedTest注解的name属性,演示代码如下,可见currentRepetition和totalRepetitions是占位符,在真正展示的时候会被分别替换成当前值和总次数:
@Order(3)
@DisplayName("重复测试,使用定制名称")
@RepeatedTest(value = 5, name="完成度:{currentRepetition}/{totalRepetitions}")
void repeatWithCustomDisplayNameTest(TestInfo testInfo, RepetitionInfo repetitionInfo) {
log.info("测试方法 [{}],当前第[{}]次,共[{}]次",
testInfo.getTestMethod().get().getName(),
repetitionInfo.getCurrentRepetition(),
repetitionInfo.getTotalRepetitions());
}
3. 嵌套测试的演示代码如下:
package com.bolingcavalry.advanced.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@Slf4j
@DisplayName("嵌套测试演示")
public class NestedTest {
@Nested
@DisplayName("查找服务相关的测试")
class FindService {
@Test
void findByIdTest() {}
@Test
void findByNameTest() {}
}
@Nested
@DisplayName("删除服务相关的测试")
class DeleteService {
@Test
void deleteByIdTest() {}
@Test
void deleteByNameTest() {}
}
}
package com.bolingcavalry.advanced.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Arrays;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
@SpringBootTest
@Slf4j
class DynamicDemoTest {
@TestFactory
Iterable<org.junit.jupiter.api.DynamicTest> testFactoryTest() {
DynamicTest firstTest = dynamicTest(
"一号动态测试用例",
() -> {
log.info("一号用例,这里编写单元测试逻辑代码");
}
);
DynamicTest secondTest = dynamicTest(
"二号动态测试用例",
() -> {
log.info("二号用例,这里编写单元测试逻辑代码");
}
);
return Arrays.asList(firstTest, secondTest);
}
}
# 并行开关true/false
junit.jupiter.execution.parallel.enabled=true
# 方法级多线程开关 same_thread/concurrent
junit.jupiter.execution.parallel.mode.default = same_thread
# 类级多线程开关 same_thread/concurrent
junit.jupiter.execution.parallel.mode.classes.default = same_thread
# 并发策略有以下三种可选:
# fixed:固定线程数,此时还要通过junit.jupiter.execution.parallel.config.fixed.parallelism指定线程数
# dynamic:表示根据处理器和核数计算线程数
# custom:自定义并发策略,通过这个配置来指定:junit.jupiter.execution.parallel.config.custom.class
junit.jupiter.execution.parallel.config.strategy = fixed
# 并发线程数,该配置项只有当并发策略为fixed的时候才有用
junit.jupiter.execution.parallel.config.fixed.parallelism = 5
package com.bolingcavalry.advanced.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SpringBootTest
@Slf4j
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class ParallelExecutionTest {
@Order(1)
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("单线程执行10次")
@RepeatedTest(value = 10, name="完成度:{currentRepetition}/{totalRepetitions}")
void sameThreadTest(TestInfo testInfo, RepetitionInfo repetitionInfo) {
log.info("测试方法 [{}],当前第[{}]次,共[{}]次",
testInfo.getTestMethod().get().getName(),
repetitionInfo.getCurrentRepetition(),
repetitionInfo.getTotalRepetitions());
}
}
@Order(2)
@Execution(ExecutionMode.CONCURRENT)
@DisplayName("多线程执行10次")
@RepeatedTest(value = 10, name="完成度:{currentRepetition}/{totalRepetitions}")
void concurrentTest(TestInfo testInfo, RepetitionInfo repetitionInfo) {
log.info("测试方法 [{}],当前第[{}]次,共[{}]次",
testInfo.getTestMethod().get().getName(),
repetitionInfo.getCurrentRepetition(),
repetitionInfo.getTotalRepetitions());
}
11. 最后是参数化测试的演示,也可以设置为多线程并行执行:
@Order(3)
@Execution(ExecutionMode.CONCURRENT)
@DisplayName("多个int型入参")
@ParameterizedTest
@ValueSource(ints = { 1,2,3,4,5,6,7,8,9,0 })
void intsTest(int candidate) {
log.info("ints [{}]", candidate);
}
至此,《JUnit5学习》系列已经全部完成,感谢您的耐心阅读,希望这个原创系列能够带给您一些有用的信息,为您的单元测试提供一些参考,如果发现文章有错误,期待您能指点一二;
微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...
https://github.com/zq2599/blog_demos
作者:Djdj
链接:http://www.javaheidong.com/blog/article/112309/893827093949aa70399a/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!