JUnit5注解学习指引
注解(Annotations)是JUnit的标志性技术,本文就来对它的20个注解,以及元注解和组合注解进行学习。
20个注解
在org.junit.jupiter.api包中定义了这些注解,它们分别是:
@Test测试方法,可以直接运行。@ParameterizedTest参数化测试,比如:@ParameterizedTest
@ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
void palindromes(String candidate) {
assertTrue(StringUtils.isPalindrome(candidate));
}
@RepeatedTest重复测试,比如:@RepeatedTest(10)
void repeatedTest() {
// ...
}
@TestFactory测试工厂,专门生成测试方法,比如:import org.junit.jupiter.api.DynamicTest; @TestFactory
Collection<DynamicTest> dynamicTestsFromCollection() {
return Arrays.asList(
dynamicTest("1st dynamic test", () -> assertTrue(isPalindrome("madam"))),
dynamicTest("2nd dynamic test", () -> assertEquals(4, calculator.multiply(2, 2)))
);
}
@TestTemplate测试模板,比如:final List<String> fruits = Arrays.asList("apple", "banana", "lemon"); @TestTemplate
@ExtendWith(MyTestTemplateInvocationContextProvider.class)
void testTemplate(String fruit) {
assertTrue(fruits.contains(fruit));
} public class MyTestTemplateInvocationContextProvider
implements TestTemplateInvocationContextProvider { @Override
public boolean supportsTestTemplate(ExtensionContext context) {
return true;
} @Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(
ExtensionContext context) { return Stream.of(invocationContext("apple"), invocationContext("banana"));
}
}
@TestTemplate必须注册一个TestTemplateInvocationContextProvider,它的用法跟@Test类似。
@TestMethodOrder指定测试顺序,比如:import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; @TestMethodOrder(OrderAnnotation.class)
class OrderedTestsDemo { @Test
@Order(1)
void nullValues() {
// perform assertions against null values
} @Test
@Order(2)
void emptyValues() {
// perform assertions against empty values
} @Test
@Order(3)
void validValues() {
// perform assertions against valid values
} }
@TestInstance是否生成多个测试实例,默认JUnit每个测试方法生成一个实例,使用这个注解能让每个类只生成一个实例,比如:@TestInstance(Lifecycle.PER_CLASS)
class TestMethodDemo { @Test
void test1() {
} @Test
void test2() {
} @Test
void test3() {
} }
@DisplayName自定义测试名字,会体现在测试报告中,比如:import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test; @DisplayName("A special test case")
class DisplayNameDemo { @Test
@DisplayName("Custom test name containing spaces")
void testWithDisplayNameContainingSpaces() {
} @Test
@DisplayName("╯°□°)╯")
void testWithDisplayNameContainingSpecialCharacters() {
} @Test
@DisplayName("")
void testWithDisplayNameContainingEmoji() {
} }
@DisplayNameGeneration测试名字统一处理,比如:import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.IndicativeSentencesGeneration;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource; class DisplayNameGeneratorDemo { @Nested
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class A_year_is_not_supported { @Test
void if_it_is_zero() {
} @DisplayName("A negative value for year is not supported by the leap year computation.")
@ParameterizedTest(name = "For example, year {0} is not supported.")
@ValueSource(ints = { -1, -4 })
void if_it_is_negative(int year) {
} } @Nested
@IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class)
class A_year_is_a_leap_year { @Test
void if_it_is_divisible_by_4_but_not_by_100() {
} @ParameterizedTest(name = "Year {0} is a leap year.")
@ValueSource(ints = { 2016, 2020, 2048 })
void if_it_is_one_of_the_following_years(int year) {
} } }
@BeforeEach在每个@Test,@RepeatedTest,@ParameterizedTest, or@TestFactory之前执行。@AfterEach在每个@Test,@RepeatedTest,@ParameterizedTest, or@TestFactory之后执行。@BeforeAll在所有的@Test,@RepeatedTest,@ParameterizedTest, and@TestFactory之前执行。@AfterAll在所有的@Test,@RepeatedTest,@ParameterizedTest, and@TestFactory之后执行。@Nested嵌套测试,一个类套一个类,例子参考上面那个。@Tag打标签,相当于分组,比如:import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test; @Tag("fast")
@Tag("model")
class TaggingDemo { @Test
@Tag("taxes")
void testingTaxCalculation() {
} }
@Disabled禁用测试,比如:import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; @Disabled("Disabled until bug #99 has been fixed")
class DisabledClassDemo { @Test
void testWillBeSkipped() {
} }
@Timeout对于test, test factory, test template, or lifecycle method,如果超时了就认为失败了,比如:class TimeoutDemo { @BeforeEach
@Timeout(5)
void setUp() {
// fails if execution time exceeds 5 seconds
} @Test
@Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
void failsIfExecutionTimeExceeds100Milliseconds() {
// fails if execution time exceeds 100 milliseconds
} }
@ExtendWith注册扩展,比如:@ExtendWith(RandomParametersExtension.class)
@Test
void test(@Random int i) {
// ...
}
JUnit5提供了标准的扩展机制来允许开发人员对JUnit5的功能进行增强。JUnit5提供了很多的标准扩展接口,第三方可以直接实现这些接口来提供自定义的行为。
@RegisterExtension通过字段注册扩展,比如:class WebServerDemo { @RegisterExtension
static WebServerExtension server = WebServerExtension.builder()
.enableSecurity(false)
.build(); @Test
void getProductList() {
WebClient webClient = new WebClient();
String serverUrl = server.getServerUrl();
// Use WebClient to connect to web server using serverUrl and verify response
assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus());
} }
@TempDir临时目录,比如:@Test
void writeItemsToFile(@TempDir Path tempDir) throws IOException {
Path file = tempDir.resolve("test.txt"); new ListWriter(file).write("a", "b", "c"); assertEquals(singletonList("a,b,c"), Files.readAllLines(file));
}
元注解和组合注解
JUnit Jupiter支持元注解,能继承后实现自定义注解,比如自定义@Fast注解:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
public @interface Fast {
}
使用:
@Fast
@Test
void myFastTest() {
// ...
}
这个@Fast注解也是组合注解,甚至可以更进一步和@Test组合:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
@Test
public @interface FastTest {
}
只用@FastTest就可以了:
@FastTest
void myFastTest() {
// ...
}
小结
本文对JUnit20个主要的注解进行了介绍和示例演示,JUnit Jupiter支持元注解,可以自定义注解,也可以把多个注解组合起来。
参考资料:
https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
https://vitzhou.gitbooks.io/junit5/content/junit/extension_model.html#概述
JUnit5注解学习指引的更多相关文章
- 转-Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable
转-http://snowolf.iteye.com/blog/1628861/ Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariab ...
- 【转】Spring 注解学习手札(超好的springmvc注解教程)
Spring 注解学习手札(一) 构建简单Web应用 Spring 注解学习手札(二) 控制层梳理 Spring 注解学习手札(三) 表单页面处理 Spring 注解学习手札(四) 持久层浅析 Spr ...
- Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable (转)
最近需要做些接口服务,服务协议定为JSON,为了整合在Spring中,一开始确实费了很大的劲,经朋友提醒才发现,SpringMVC已经强悍到如此地步,佩服! 相关参考: Spring 注解学习手札(一 ...
- Spring 注解学习手札(七) 补遗——@ResponseBody,@RequestBody,@PathVariable(转)
最近需要做些接口服务,服务协议定为JSON,为了整合在Spring中,一开始确实费了很大的劲,经朋友提醒才发现,SpringMVC已经强悍到如此地步,佩服! 相关参考: Spring 注解学习手札(一 ...
- Spring @Autowired 注解 学习资料
Spring @Autowired 注解 学习资料 网址 Spring @Autowired 注解 https://wiki.jikexueyuan.com/project/spring/annota ...
- 注解学习(模仿springMvc的注解注入方式)
最近在看springMvc的源码,看到了该框架的注入注解的部分觉的有点吃力,可能还是对注解的方面的知识还认识的不够深刻,所以特意去学习注解方面的知识.由于本人也是抱着学习的态度来阅读源码,若文章在表述 ...
- spring mvc 注解 学习笔记(一)
以前接触过spring,但是没有接触spring mvc 以及注解的应用,特习之,记之: 注解了解 @Component 是通用标注, @Controller 标注web控制器, @Service 标 ...
- Spring的IOC注解学习
先引入jar包,common-annotations.jar 接着上代码: 1.dao接口 package com.dao; public interface OkpDao { public void ...
- Struts2注解学习1
这是开博的第一篇,我希望每天把我学到的东西记录下来,成为一个知识库,方便以后的学习和分享 在项目中看到用struts2注解来做,很方便,做了一个用户登录的例子 1.加载所需jar包 commons-f ...
随机推荐
- [bug] Flask css 不更新
参考 https://blog.csdn.net/weixin_30454481/article/details/97108510
- [Qt] 基本概念
QObject :所有 Qt 类的基类 QWidget类:包含所有组件的类 Widgets:组件,组成Qt界面的基本元素 window:界面,是不含有父组件的组件 Child Widgets:子组件, ...
- 【转载】在python的class中的,self到底是什么?
在python的class中的,self到底是什么? 答案:self可以理解为一个字典变量,内部存的就是对象的数据属性.如:{'name':'zhang','age':'18'}就是这些. 注意只 ...
- linux基本命令随笔
cd(change directory) 不跟参数,直接进入当前登录用户的家目录 . 代表当前目录 .. 代表上级目录 ls(list) -l 显示文件详细信息 -a 显示隐藏文件 -S 以文件大小排 ...
- 关于UCOSII的学习资料
UCOSII学习资料: 在战舰的A盘资料包中 ->软件资料->ucosii 有一个叫做简易OS讲解的文档,此文从简单的OS将其,通俗易懂的讲解大体的OS运行原理,任务调度的实现过程,是入门 ...
- centos7 Nacos+Elasticsearch+SkyWalking
安装包下载 nacos 下载地址:https://github.com/alibaba/nacos/releases es 下载地址:https://www.elastic.co/cn/downloa ...
- docker 部署应用
Docker 部署应用 所需环境 Linux系统:centos7 (推荐7.4) Docker环境:V1.13.1 镜像:应用镜像包 docker部署和基本命令: 1. docker环境搭建 a) ...
- CentOS7 删除virbr0虚拟网卡
在CentOS 7的安装过程中如果有选择相关虚拟化的的服务安装系统后,启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡,这个是因为在虚拟化中有使用到libvirtd服务生成的,如果不需要可 ...
- MyBatisPlus详细总结记录
本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com 小 Hub 领读: 一篇写得非常详细的文章,增删改查,各种插件,让你测底熟悉 mybatis plus. 作者:yo ...
- 五、SVM推导过程
SVM 时间复杂度一般为O(N³) 最重要的是推导过程 NIPS(机器学习顶级会议) 如果给定一个训练集,我们的目标是给定一个边界(一条线),离他最近的训练集样本路越宽越好 下面的几张图反映了SVM的 ...