Table of Contents
ToggleSpring Boot JUnit 5
通常任何系統都會劃分為不同的模組和元件,單獨測試一個程式、過程或方法時,稱之為單元測試, JUnit5 Tutorial 用於驗證相關的一小段程式碼是否能正常工作,與原 JUnit 4 版本有些許的差異,本篇增加了相依套件及採用單元測試來驗證產出結果。
功能簡介
JUnit 是一個編寫和運行可重複的自動化測試的測試框架,一個 Unit 可以是單支程式、過程或方法,而在物件導向的程式設計中,最小的單元就是方法,針對程式撰寫時的最小單位,進行正確性驗證的測試,從單元測試、整合測試等,並有測試分類、測試運行器等功能,保證程式碼能夠按照預期結果執行。
檔案目錄
./
+- build.gradle
+- src
+- test
+- junit5
+- java
+- MessageSourceJUnit5Test.java
Gradle
build.gradle
設定 JUnit 5 Gradle 。
Spring Boot Starter Test 排除 JUnit 4 ,增加 JUnit 5。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage。
JUnit Platform 是提供測試框架執行環境的平台。
JUnit Jupiter 是新的 JUnit 5 子項目,提供了一個基於平台測試執行 Jupiter 的測試引擎。
JUnit Vintage 提供 JUnit 3 / 4 的測試引擎。
plugins 增加 Spring Boot 、Dependency Management 。
修改完後,點右鍵,Gradle -> Refresh Gradle Project 。
buildscript {
group 'org.ruoxue.spring-boot-168'
version = '0.0.1-SNAPSHOT'
ext {
springBootVersion = '2.1.7.RELEASE'
junit5Version = '5.7.2'
junitPlatformVersion = '1.7.2'
}
}
plugins {
id 'java-library'
id 'eclipse'
}
dependencies {
testImplementation ("org.springframework.boot:spring-boot-starter-test:${springBootVersion}") {
exclude group: 'junit', module: 'junit'
}
testImplementation "org.junit.jupiter:junit-jupiter-api:${junit5Version}"
testRuntimeOnly "org.junit.platform:junit-platform-commons:${junitPlatformVersion}"
testRuntimeOnly "org.junit.platform:junit-platform-engine:${junitPlatformVersion}"
testRuntimeOnly "org.junit.platform:junit-platform-launcher:${junitPlatformVersion}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit5Version}"
testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit5Version}"
}
test {
useJUnitPlatform()
}
單元測試
Spring Boot Test JUnit 5 主要目的是取得訊息以進行斷言,驗證實際結果是否符合預期結果。
MessageSourceJUnit5Test.java
新增單元測試,驗證是否符合預期,增加 @ExtendWith(SpringExtension.class)。
@Test、assertEquals 改為使用 jupiter package。
package org.ruoxue.spring_boot_168.test.junit5;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Locale;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.ruoxue.spring_boot_168.Application;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.MessageSource;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = Application.class)
public class MessageSourceJUnit5Test {
@Autowired
private MessageSource messageSource;
@Test
public void getMessage_zh_TW() {
String name = messageSource.getMessage("spring-boot-168.contact.name", (Object[]) null,
Locale.TRADITIONAL_CHINESE);
System.out.println("name: " + name);
assertEquals("若雪", name);
String url = messageSource.getMessage("spring-boot-168.contact.url", (Object[]) null,
Locale.TRADITIONAL_CHINESE);
System.out.println("url: " + url);
assertEquals("https://www.ruoxue.org", url);
String email = messageSource.getMessage("spring-boot-168.contact.email", (Object[]) null,
Locale.TRADITIONAL_CHINESE);
System.out.println("email: " + email);
assertEquals("ruoxueorg@gmail.com", email);
}
@Test
public void getMessage_en_US() {
String name = messageSource.getMessage("spring-boot-168.contact.name", (Object[]) null, Locale.US);
System.out.println("name: " + name);
assertEquals("Ruoxue", name);
String url = messageSource.getMessage("spring-boot-168.contact.url", (Object[]) null, Locale.US);
System.out.println("url: " + url);
assertEquals("https://www.ruoxue.org", url);
String email = messageSource.getMessage("spring-boot-168.contact.email", (Object[]) null, Locale.US);
System.out.println("email: " + email);
assertEquals("ruoxueorg@gmail.com", email);
}
}
getMessage_zh_TW
JUnit 5 Tutorial 測試方法上點右鍵執行 Run As -> JUnit Test ,查看 console。
name: 若雪
url: https://www.ruoxue.org
email: ruoxueorg@gmail.com
getMessage_en_US
JUnit 5 Tutorial 測試方法上點右鍵執行 Run As -> JUnit Test ,查看 console。
name: Ruoxue
url: https://www.ruoxue.org
email: ruoxueorg@gmail.com
故障排除
缺少 junit-platform
執行 Spring Boot Test JUnit 5 ,拋出例外,發生錯誤,stack trace 如下:
java.lang.BootstrapMethodError: java.lang.NoClassDefFoundError: org/junit/platform/engine/EngineDiscoveryListener
at org.junit.platform.launcher.core.ListenerRegistry.forLauncherDiscoveryListeners(ListenerRegistry.java:36)
at org.junit.platform.launcher.core.DefaultLauncher.<init>(DefaultLauncher.java:40)
at org.junit.platform.launcher.core.LauncherFactory.createDefaultLauncher(LauncherFactory.java:134)
at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:125)
at org.junit.platform.launcher.core.LauncherFactory.create(LauncherFactory.java:109)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.<init>(JUnit5TestLoader.java:37)
這是因為少了 junit-platform-launcher 測試框架的執行環境,所以在 build.gradle 加上相依套件,修改完後,點右鍵,Gradle -> Refresh Gradle Project ,再次執行,就能順利運行。
// 修改後
testRuntimeOnly "org.junit.platform:junit-platform-launcher"
缺少 Spring SpringBootTest
執行 Spring Boot Testing JUnit 5 ,拋出例外,發生錯誤,stack trace 如下:
org.springframework.context.NoSuchMessageException: No message found under code 'spring-boot-168.contact.name' for locale 'zh_TW'.
at org.springframework.context.support.DelegatingMessageSource.getMessage(DelegatingMessageSource.java:76)
at test.MessageSourceJUnit5Test.getMessage_zh_TW(MessageSourceJUnit5Test.java:22)
這是因為少了@SpringBootTest 註解,在類別開頭加上,修改完後,再次執行,就能順利運行。
// 修改前
public class MessageSourceJUnit5Test {
// 修改後
@SpringBootTest(classes = Application.class)
public class MessageSourceJUnit5Test {
心得分享
Java Unit Testing with JUnit 5 從 JUnit 4 升版後,原本的 Package 會有所改變,使用的 Annotation 也會略有不同,參照 build.gradle 的設定,JUnit Vintage 套件支援 JUint 4 ,同時 JUnit 5 也能並存,比照先前 JUnit 4 的用法,請參考此篇: