JUnit5學習之五:標籤(Tag)和自定義註解

歡迎訪問個人GitHub

https://github.com/zq2599/blog_demosjava

內容:全部原創文章分類彙總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;git

關於《JUnit5學習》系列

《JUnit5學習》系列旨在經過實戰提高SpringBoot環境下的單元測試技能,一共八篇文章,連接以下:程序員

  1. 基本操做
  2. Assumptions類
  3. Assertions類
  4. 按條件執行
  5. 標籤(Tag)和自定義註解
  6. 參數化測試(Parameterized Tests)基礎
  7. 參數化測試(Parameterized Tests)進階
  8. 綜合進階(終篇)

本篇概覽

本文是《JUnit5學習》系列的第五篇,一塊兒來學習JUnit5的標籤(Tag)功能,設想一個工程中的有不少測試類和測試方法,有的場景只需執行其中一部分測試方法,如何實現呢?此時Junit的標籤功能就派上用場了,我們能夠按須要給測試類或者方法打標籤,在執行單元測試時按照標籤進行過濾,學完了標籤再來了解JUnit5對自定義註解的支持狀況,本篇大綱以下:github

  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註解:
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裏面填寫過濾規則,後面會詳細講解這個規則,這裏先填個已存在的標籤importantspring

在這裏插入圖片描述
4. 建立好JUnit配置後,執行下圖紅框中的操做便可執行單元測試:shell

在這裏插入圖片描述

  1. 執行結果以下,全部打了important標籤的測試方法被執行:

在這裏插入圖片描述

用maven命令時作標籤過濾

  1. 前面試過IDEA上按標籤過濾測試方法,其實用maven命令執行單元測試的時候也能按標籤來過濾,接下來試試;
  2. 在父工程junitpractice的pom.xml所在目錄下,執行如下命令,便可開始單元測試,而且只執行帶有標籤的方法:
mvn clean test -Dgroups="important"
  1. 執行完畢後結果以下:

在這裏插入圖片描述
4. 翻看日誌,可見只有打了important標籤的測試方法被執行了,以下圖紅框所示:數據庫

在這裏插入圖片描述

  1. 再看看其餘子工程的執行狀況,用前一篇文章裏的conditional爲例,可見沒有任何測試方法被執行,以下圖紅框所示:

在這裏插入圖片描述

  1. 再去看看surefire插件給出的測試報告,報告文件在junitpractice\tag\target\surefire-reports目錄下,下圖紅框中的文件就是測試報告:
    在這裏插入圖片描述express

  2. 打開上圖紅框中的一個文件,以下圖紅框,可見只有打了important標籤的測試方法被執行了:api

在這裏插入圖片描述

  • 以上就是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

在這裏插入圖片描述
5. 再次執行這個配置,結果以下圖紅框所示,只有這三個方法被執行:first1Test、first3Test、second3Test,可見標籤表達式生效了:

在這裏插入圖片描述
6. 在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的標籤過濾和自定義註解功能都學習完成了,有了這些能力,我們能夠更加靈活和爲所欲爲的應付不一樣的場景和需求;

你不孤單,欣宸原創一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 數據庫+中間件系列
  6. DevOps系列

歡迎關注公衆號:程序員欣宸

微信搜索「程序員欣宸」,我是欣宸,期待與您一同暢遊Java世界...
https://github.com/zq2599/blog_demos

相關文章
相關標籤/搜索