JUnit5学习之五:标签(Tag)和自定义注解

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

关于《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文件夹下,如下图红框所示:
    在这里插入图片描述

  2. junitpractice是父子结构的工程,本篇的代码在tag子工程中,如下图:
    在这里插入图片描述

设置标签

  1. 在父工程junitpractice里新建名为tag的子工程,今天的单元测试代码都写在这个tag工程中;
  2. 一共写两个测试类,第一个FirstTest.java如下,可见类上有Tag注解,值为first,另外每个方法上都有Tag注解,其中first1Test方法有两个Tag注解:
package com.bolingcavalry.tag.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest
@Slf4j
@Tag("first")
public class FirstTest {

    @Test
    @Tag("easy")
    @Tag("important")
    @DisplayName("first-1")
    void first1Test() {
        log.info("first1Test");
        assertEquals(2, Math.addExact(1, 1));
    }

    @Test
    @Tag("easy")
    @DisplayName("first-2")
    void first2Test() {
        log.info("first2Test");
        assertEquals(2, Math.addExact(1, 1));
    }

    @Test
    @Tag("hard")
    @DisplayName("first-3")
    void first3Test() {
        log.info("first3Test");
        assertEquals(2, Math.addExact(1, 1));
    }
}
  1. 第二个测试类SecondTest.java,也是类和方法都有Tag注解:
package com.bolingcavalry.tag.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;

@SpringBootTest
@Slf4j
@Tag("second")
public class SecondTest {

    @Test
    @Tag("easy")
    @DisplayName("second-1")
    void second1Test() {
        log.info("second1Test");
        assertEquals(2, Math.addExact(1, 1));
    }

    @Test
    @Tag("easy")
    @DisplayName("second-2")
    void second2Test() {
        log.info("second2Test");
        assertEquals(2, Math.addExact(1, 1));
    }

    @Test
    @Tag("hard")
    @Tag("important")
    @DisplayName("second-3")
    void second3Test() {
        log.info("second3Test");
        assertEquals(2, Math.addExact(1, 1));
    }
}
  • 以上就是打好了标签的测试类和测试方法了,接下来看看如何通过这些标签对测试方法进行过滤,执行单元测试有三种常用方式,咱们挨个尝试每种方式如何用标签过滤;

在IDEA中做标签过滤

  1. 如下图所示,点击红框中的Edit Configurations…
    在这里插入图片描述
  2. 如下图红框,在弹出的窗口上新增一个JUnit配置:
    在这里插入图片描述
  3. 接下来的操作如下图所示,Test kind选择Tags,就会按照标签过滤测试方法,Tag expression里面填写过滤规则,后面会详细讲解这个规则,这里先填个已存在的标签important
    在这里插入图片描述
  4. 创建好JUnit配置后,执行下图红框中的操作即可执行单元测试:
    在这里插入图片描述
  5. 执行结果如下,所有打了important标签的测试方法被执行:
    在这里插入图片描述

用maven命令时做标签过滤

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

  2. 翻看日志,可见只有打了important标签的测试方法被执行了,如下图红框所示:
    在这里插入图片描述

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

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

  5. 打开上图红框中的一个文件,如下图红框,可见只有打了important标签的测试方法被执行了:
    在这里插入图片描述

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

用surefire插件时做标签过滤

  1. surefire是个测试引擎(TestEngine),以maven插件的方式来使用,打开tag子工程的pom.xml文件,将build节点配置成以下形式,可见groups就是标签过滤节点,另外excludedGroups节点制定的hard标签的测试方法不会执行:
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <configuration>
                    <!--要执行的标签-->
                    <groups>important</groups>
                    <!--不要执行的标签-->
                    <excludedGroups>hard</excludedGroups>
                </configuration>
            </plugin>
        </plugins>
    </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
    在这里插入图片描述
  2. 再次执行这个配置,结果如下图红框所示,只有这三个方法被执行:first1Test、first3Test、second3Test,可见标签表达式生效了:
    在这里插入图片描述
  3. 在maven命令和surefire插件中使用标签表达式的操作就不在文中执行了,请您自行验证;

自定义注解

  1. JUnit支持自定义注解,先回顾之前的代码,看咱们是如何给方法打标签的,以first3Test方法为例:
    @Test
    @Tag("hard")
    @DisplayName("first-3")
    void first3Test() {
        log.info("first3Test");
        assertEquals(2, Math.addExact(1, 1));
    }
  1. 接下来咱们创建一个注解,将@Tag(“hard”)替换掉,新注解的源码如下,可见仅是一个普通的注解定义:
package com.bolingcavalry.tag.service.impl;

import org.junit.jupiter.api.Tag;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("hard")
public @interface Hard {
}
  1. 修改first3Test方法的注解,去掉@Tag(“hard”),改为@Hard
    @Test
    @Hard
    @DisplayName("first-3")
    void first3Test() {
        log.info("first3Test");
        assertEquals(2, Math.addExact(1, 1));
    }
  1. 执行前面创建的tag-important配置,可见hard标签的过滤依旧有效:
    在这里插入图片描述

更加简化的自定义注解

  1. 上述Hard注解取代了@Tag(“hard”),其实还可以更进一步对已有注解做简化,下面是个新的注解:HardTest.java,和Hard.java相比,多了个@Test,作用是集成了Test注解的能力
package com.bolingcavalry.tag.service.impl;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("hard")
@Test
public @interface HardTest {
}
  1. 于是,first3Test方法的注解可以改成下面的效果,可见Test和Tag注解都去掉了:
    @HardTest
    @DisplayName("first-3")
    void first3Test() {
        log.info("first3Test");
        assertEquals(2, Math.addExact(1, 1));
    }
  1. 执行前面创建的tag-important配置,可见hard标签的过滤依旧有效:
    在这里插入图片描述

标签命名规范

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

  1. 标签名左右两侧的空格是无效的,执行测试的时候会做trim处理,例如下面这个标签会被当作hard来过滤:
    在这里插入图片描述
  2. 标签名不能有这六个符号, ( ) & | !
  • 至此,JUnit5的标签过滤和自定义注解功能都学习完成了,有了这些能力,咱们可以更加灵活和随心所欲的应付不同的场景和需求;

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

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

92讲视频课+16大项目实战+源码+¥800元课程礼包+讲师社群1V1答疑+社群闭门分享会=99元   为什么学习数据分析?       人工智能、大数据时代有什么技能是可以运用在各种行业的?数据分析就是。       从海量数据中获得别人看不见的信息,创业者可以通过数据分析来优化产品,营销人员可以通过数据分析改进营销策略,产品经理可以通过数据分析洞察用户习惯,金融从业者可以通过数据分析规避投资风险,程序员可以通过数据分析进一步挖掘出数据价值,它和编程一样,本质上也是一个工具,通过数据来对现实事物进行分析和识别的能力。不管你从事什么行业,掌握了数据分析能力,往往在其岗位上更有竞争力。    本课程共包含五大模块: 一、先导篇: 通过分析数据分析师的一天,让学员了解全面了解成为一个数据分析师的所有必修功法,对数据分析师不在迷惑。   二、基础篇: 围绕Python基础语法介绍、数据预处理、数据可视化以及数据分析与挖掘......这些核心技能模块展开,帮助你快速而全面的掌握和了解成为一个数据分析师的所有必修功法。   三、数据采集篇: 通过网络爬虫实战解决数据分析的必经之路:数据从何来的问题,讲解常见的爬虫套路并利用三大实战帮助学员扎实数据采集能力,避免没有数据可分析的尴尬。   四、分析工具篇: 讲解数据分析避不开的科学计算库Numpy、数据分析工具Pandas及常见可视化工具Matplotlib。   五、算法篇: 算法是数据分析的精华,课程精选10大算法,包括分类、聚类、预测3大类型,每个算法都从原理和案例两个角度学习,让你不仅能用起来,了解原理,还能知道为什么这么做。
【为什么还需要学习C++?】 你是否接触很多语言,但从来没有了解过编程语言的本质? 你是否想成为一名资深开发人员,想开发别人做不了的高性能程序? 你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹?   那么C++就是你个人能力提升,职业之路进阶的不二之选。 【课程特色】 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。 2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。 3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。 【学完后我将达到什么水平?】 1.对C++的各个知识能够熟练配置、开发、部署; 2.吊打一切关于C++的笔试面试题; 3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。 【面向人群】 1.希望一站式快速入门的C++初学者; 2.希望快速学习 C++、掌握编程要义、修炼内功的开发者; 3.有志于挑战更高级的开发项目,成为资深开发的工程师。 【课程设计】 本课程包含3大模块 基础篇 本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。 进阶篇 本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。 提升篇: 本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页