欢迎访问我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;

关于《JUnit5学习》系列

《JUnit5学习》系列旨在通过实战提升SpringBoot环境下的单元测试技能,一共八篇文章,链接如下:

  1. 基本操作
  2. Assumptions类
  3. Assertions类
  4. 按条件执行
  5. 标签(Tag)和自定义注解
  6. 参数化测试(Parameterized Tests)基础
  7. 参数化测试(Parameterized Tests)进阶
  8. 综合进阶(终篇)

本篇概览

本文是《JUnit5学习》系列的第五篇,一起来学习JUnit5的标签(Tag)功能,设想一个工程中的有很多测试类和测试方法,有的场景只需执行其中一部分测试方法,如何实现呢?此时Junit的标签功能就派上用场了,咱们可以按需要给测试类或者方法打标签,在执行单元测试时按照标签进行过滤,学完了标签再来了解JUnit5对自定义注解的支持情况,本篇大纲如下:

  1. 设置标签
  2. 在IDEA中做标签过滤
  3. 用maven命令时做标签过滤
  4. 用surefire插件时做标签过滤
  5. 标签表达式
  6. 自定义注解
  7. 更加简化的自定义注解
  8. 标签命名规范

源码下载

  1. 如果您不想编码,可以在GitHub下载所有源码,地址和链接信息如下表所示:
名称 链接 备注
项目主页 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协议
  1. 这个git项目中有多个文件夹,本章的应用在junitpractice文件夹下,如下图红框所示:

  1. junitpractice是父子结构的工程,本篇的代码在tag子工程中,如下图:

设置标签

  1. 在父工程junitpractice里新建名为tag的子工程,今天的单元测试代码都写在这个tag工程中;
  2. 一共写两个测试类,第一个FirstTest.java如下,可见类上有Tag注解,值为first,另外每个方法上都有Tag注解,其中first1Test方法有两个Tag注解:
  1. package com.bolingcavalry.tag.service.impl;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.junit.jupiter.api.DisplayName;
  4. import org.junit.jupiter.api.Tag;
  5. import org.junit.jupiter.api.Test;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. import static org.junit.jupiter.api.Assertions.assertEquals;
  8. @SpringBootTest
  9. @Slf4j
  10. @Tag("first")
  11. public class FirstTest {
  12. @Test
  13. @Tag("easy")
  14. @Tag("important")
  15. @DisplayName("first-1")
  16. void first1Test() {
  17. log.info("first1Test");
  18. assertEquals(2, Math.addExact(1, 1));
  19. }
  20. @Test
  21. @Tag("easy")
  22. @DisplayName("first-2")
  23. void first2Test() {
  24. log.info("first2Test");
  25. assertEquals(2, Math.addExact(1, 1));
  26. }
  27. @Test
  28. @Tag("hard")
  29. @DisplayName("first-3")
  30. void first3Test() {
  31. log.info("first3Test");
  32. assertEquals(2, Math.addExact(1, 1));
  33. }
  34. }
  1. 第二个测试类SecondTest.java,也是类和方法都有Tag注解:
  1. package com.bolingcavalry.tag.service.impl;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.junit.jupiter.api.DisplayName;
  4. import org.junit.jupiter.api.Tag;
  5. import org.junit.jupiter.api.Test;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. import static org.junit.jupiter.api.Assertions.assertEquals;
  8. @SpringBootTest
  9. @Slf4j
  10. @Tag("second")
  11. public class SecondTest {
  12. @Test
  13. @Tag("easy")
  14. @DisplayName("second-1")
  15. void second1Test() {
  16. log.info("second1Test");
  17. assertEquals(2, Math.addExact(1, 1));
  18. }
  19. @Test
  20. @Tag("easy")
  21. @DisplayName("second-2")
  22. void second2Test() {
  23. log.info("second2Test");
  24. assertEquals(2, Math.addExact(1, 1));
  25. }
  26. @Test
  27. @Tag("hard")
  28. @Tag("important")
  29. @DisplayName("second-3")
  30. void second3Test() {
  31. log.info("second3Test");
  32. assertEquals(2, Math.addExact(1, 1));
  33. }
  34. }
  • 以上就是打好了标签的测试类和测试方法了,接下来看看如何通过这些标签对测试方法进行过滤,执行单元测试有三种常用方式,咱们挨个尝试每种方式如何用标签过滤;

在IDEA中做标签过滤

  1. 如下图所示,点击红框中的Edit Configurations...:



2. 如下图红框,在弹出的窗口上新增一个JUnit配置:



3. 接下来的操作如下图所示,Test kind选择Tags,就会按照标签过滤测试方法,Tag expression里面填写过滤规则,后面会详细讲解这个规则,这里先填个已存在的标签important:



4. 创建好JUnit配置后,执行下图红框中的操作即可执行单元测试:

  1. 执行结果如下,所有打了important标签的测试方法被执行:

用maven命令时做标签过滤

  1. 前面试过IDEA上按标签过滤测试方法,其实用maven命令执行单元测试的时候也能按标签来过滤,接下来试试;
  2. 在父工程junitpractice的pom.xml所在目录下,执行以下命令,即可开始单元测试,并且只执行带有标签的方法:
  1. mvn clean test -Dgroups="important"
  1. 执行完毕后结果如下:



4. 翻看日志,可见只有打了important标签的测试方法被执行了,如下图红框所示:

  1. 再看看其他子工程的执行情况,用前一篇文章里的conditional为例,可见没有任何测试方法被执行,如下图红框所示:

  1. 再去看看surefire插件给出的测试报告,报告文件在junitpractice\tag\target\surefire-reports目录下,下图红框中的文件就是测试报告:

  2. 打开上图红框中的一个文件,如下图红框,可见只有打了important标签的测试方法被执行了:

  • 以上就是maven命令执行单元测试时使用标签过滤的方法,接下来试试在使用maven-surefire-plugin插件时如何通过做标签过滤

用surefire插件时做标签过滤

  1. surefire是个测试引擎(TestEngine),以maven插件的方式来使用,打开tag子工程的pom.xml文件,将build节点配置成以下形式,可见groups就是标签过滤节点,另外excludedGroups节点制定的hard标签的测试方法不会执行:
  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-maven-plugin</artifactId>
  6. </plugin>
  7. <plugin>
  8. <artifactId>maven-surefire-plugin</artifactId>
  9. <version>2.22.2</version>
  10. <configuration>
  11. <!--要执行的标签-->
  12. <groups>important</groups>
  13. <!--不要执行的标签-->
  14. <excludedGroups>hard</excludedGroups>
  15. </configuration>
  16. </plugin>
  17. </plugins>
  18. </build>
  1. 在tag子工程的pom.xml所在目录,执行命令mvn clean test即可开始单元测试,结果如下,可见打了important标签的first1Test被执行,而second3Test方法尽管有important标签,但是由于其hard标签已经被设置为不执行,因此second3Test没有被执行:

标签表达式

  1. 前面咱们用三种方法执行了单元测试,每次都是用important标签过滤,其实除了指定标签,JUnit还支持更复杂的标签过滤,即标签表达式
  2. 所谓标签表达式,就是用"非"、"与"、"或"这三种操作符将更多的标签连接起来,实现更复杂的过滤逻辑;
  3. 上述三种操作符的定义和用法如下表:
操作符 作用 举例 举例说明
& important & easy 既有important,又有easy标签,
在本文是first1Test
! important & !easy 有important,同时又没有easy标签,
在本文是second3Test
| important | hard 有important标签的,再加上有hard标签的,
在本文是first1Test、first3Test、second3Test
  1. 试试标签表达式的效果,如下图红框,修改前面创建好的IDEA配置,从之前的important改为important | hard:



5. 再次执行这个配置,结果如下图红框所示,只有这三个方法被执行:first1Test、first3Test、second3Test,可见标签表达式生效了:



6. 在maven命令和surefire插件中使用标签表达式的操作就不在文中执行了,请您自行验证;

自定义注解

  1. JUnit支持自定义注解,先回顾之前的代码,看咱们是如何给方法打标签的,以first3Test方法为例:
  1. @Test
  2. @Tag("hard")
  3. @DisplayName("first-3")
  4. void first3Test() {
  5. log.info("first3Test");
  6. assertEquals(2, Math.addExact(1, 1));
  7. }
  1. 接下来咱们创建一个注解,将@Tag("hard")替换掉,新注解的源码如下,可见仅是一个普通的注解定义:
  1. package com.bolingcavalry.tag.service.impl;
  2. import org.junit.jupiter.api.Tag;
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. @Target({ ElementType.TYPE, ElementType.METHOD })
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Tag("hard")
  10. public @interface Hard {
  11. }
  1. 修改first3Test方法的注解,去掉@Tag("hard"),改为@Hard:
  1. @Test
  2. @Hard
  3. @DisplayName("first-3")
  4. void first3Test() {
  5. log.info("first3Test");
  6. assertEquals(2, Math.addExact(1, 1));
  7. }
  1. 执行前面创建的tag-important配置,可见hard标签的过滤依旧有效:

更加简化的自定义注解

  1. 上述Hard注解取代了@Tag("hard"),其实还可以更进一步对已有注解做简化,下面是个新的注解:HardTest.java,和Hard.java相比,多了个@Test,作用是集成了Test注解的能力
  1. package com.bolingcavalry.tag.service.impl;
  2. import org.junit.jupiter.api.Tag;
  3. import org.junit.jupiter.api.Test;
  4. import java.lang.annotation.ElementType;
  5. import java.lang.annotation.Retention;
  6. import java.lang.annotation.RetentionPolicy;
  7. import java.lang.annotation.Target;
  8. @Target({ ElementType.TYPE, ElementType.METHOD })
  9. @Retention(RetentionPolicy.RUNTIME)
  10. @Tag("hard")
  11. @Test
  12. public @interface HardTest {
  13. }
  1. 于是,first3Test方法的注解可以改成下面的效果,可见Test和Tag注解都去掉了:
  1. @HardTest
  2. @DisplayName("first-3")
  3. void first3Test() {
  4. log.info("first3Test");
  5. assertEquals(2, Math.addExact(1, 1));
  6. }
  1. 执行前面创建的tag-important配置,可见hard标签的过滤依旧有效:

标签命名规范

最后一起来看看给标签取名时有哪些要注意的地方:

  1. 标签名左右两侧的空格是无效的,执行测试的时候会做trim处理,例如下面这个标签会被当作hard来过滤:



2. 标签名不能有这六个符号, ( ) & | !

  • 至此,JUnit5的标签过滤和自定义注解功能都学习完成了,有了这些能力,咱们可以更加灵活和随心所欲的应付不同的场景和需求;

你不孤单,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢迎关注公众号:程序员欣宸

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...

https://github.com/zq2599/blog_demos

JUnit5学习之五:标签(Tag)和自定义注解的更多相关文章

  1. JUnit5学习之一:基本操作

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  2. JUnit5学习之二:Assumptions类

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  3. JUnit5学习之三:Assertions类

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  4. JUnit5学习之四:按条件执行

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. JUnit5学习之六:参数化测试(Parameterized Tests)基础

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. JUnit5学习之七:参数化测试(Parameterized Tests)进阶

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  7. JUnit5学习之八:综合进阶(终篇)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  8. AOP自定义注解鉴权

    刚出来工作那会或者在学校的时候,经常听到说AOP(面向对象编程,熟称切面)的用途是日志.鉴权等.但是那会不会,后面学会了,又没有写博客记录,今天写给大伙,希望能帮到大家 一.学习目标:利用AOP+自定 ...

  9. [原创]java WEB学习笔记42:带标签体的自定义标签,带父标签的自定义标签,el中自定义函数,自定义标签的小结

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

随机推荐

  1. 在VirtualBox上安装Ubuntu-20.04

    本文主要介绍如何在VirtualBox上安装Ubuntu-20.04 目录 下载VirtualBox 下载Ubuntu-20.04镜像 新建虚拟机 第一步:打开VirtualBox 第二步:设置虚拟机 ...

  2. 【uva 10048】Audiophobia(图论--Floyd算法)

    题意:有一个N点M边的无向带权图,边权表示路径上的噪声值.有Q个询问,输出 x,y 两点间的最大噪声值最小的路径的该值.(N≤100,M≤1000,Q≤10000) 解法:N值小,且问多对点之间的路径 ...

  3. Centos7 搭建Nginx+rtmp+hls直播推流服务器

    1 准备工具 使用yum安装git [root~]# yum -y install git 下载nginx-rtmp-module,官方github地址 // 通过git clone 的方式下载到服务 ...

  4. WSL2 Ubuntu apt-get update失败

    情况: 这个问题在github上也有讨论:https://github.com/microsoft/WSL/issues/4342 不过经过我的尝试,是DNS问题,这是默认的配置: 这个配置来自win ...

  5. vlc音视频开发(二)环境搭建(VS篇)

    来源:微信公众号「编程学习基地」 目录 简介 VS配置vlc开发环境 下载vlc源码 创建vlc环境 测试vlc代码 运行vlc程序 完成项目文件获取 简介 VLC 是一款自由.开源的跨平台多媒体播放 ...

  6. MiniSMB 网络性能测试 免费版本安装指南

    1) 烧录Image至USB 在Linux环境下可以运行以下命令(假设usb设备符号为/dev/sdb): root# tar -Jxf minismb-free-edition.img.tar.xz ...

  7. LEETCODE - 160【相交链表】

    /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode ...

  8. C、C++语言中参数的压栈顺序

    要回答这个问题,就不得不谈一谈printf()函数,printf函数的原型是:printf(const char* format,-) 没错,它是一个不定参函数,那么我们在实际使用中是怎么样知道它的参 ...

  9. 2019牛客多校第二场E MAZE(线段树 + 矩阵)题解

    题意: n * m的矩阵,为0表示可以走,1不可以走.规定每走一步只能向下.向左.向右走.现给定两种操作: 一.1 x y表示翻转坐标(x,y)的0.1. 二.2 x y表示从(1,x)走到(n,y) ...

  10. Dart SDK All In One

    Dart SDK All In One Dart SDK archive https://dart.dev/tools/sdk/archive https://dart.dev/get-dart Th ...