全テストの実行前に static 変数のフラグをセットしたかったため、そうしたことのできる方法を探したところ、JUnit 5 と IntelliJ や Maven Surefire Plugin の組み合わせで実現可能だとわかったためご紹介します。
JUnit 5 User Guide の 6.4.5. Registering a LauncherSessionListener を読めばわかることではあるのですが、もっと簡単な例と実行結果が載っている日本語の記事があるといいんじゃないかと思って執筆しました。
前提
- Gradle 4.6 以上
- Maven Surefire/Failsafe 3.0.0-M6 以上
- IntelliJ IDEA 2017.3 以上
Maven では Surefire/Failsafe Plugin のプレリリース版を使っている点にご注意ください。
実現方法
Maven でプロジェクトを作成しました。
src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener に LauncherSessionListener を実装したクラスの完全修飾クラス名を記載します。
LauncherSessionListener を実装したクラスでは、launcherSessionOpened
メソッドをオーバーライドし、その中にやりたい処理を記述します。
ディレクトリー構成とファイル内容の例
.
├── pom.xml
└── src
└── test
├── java
│ ├── ATest.java
│ ├── BTest.java
│ ├── MyIT.java
│ └── org
│ └── example
│ └── MySessionListener.java
└── resources
└── META-INF
└── services
└── org.junit.platform.launcher.LauncherSessionListener
pom.xml は以下のようにしました。
- Surefire Plugin を使って test フェイズに Test*、*Test、*Tests、*TestCase クラスを対象に単体テストを実行します。
- Failsafe Plugin を使って verify フェイズに IT*、*IT、*ITCase クラスを対象に結合テストを実行します。IT は Integration Test の略で結合テスト (もしくは統合テスト) のことです。
-
goals
内にintegration-test
やverify
と書く必要があります。さっき忘れてました💦
-
- Java 17 を使っていますが、もっと古くても大丈夫なはずです。
- 冒頭の
artifactId
のjunit-platform-launcher-session-listener
となっている箇所は、my-example-project
など適当な内容で大丈夫です。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>junit-platform-launcher-session-listener</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.9.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M8</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M8</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
1行だけの org.junit.platform.launcher.LauncherSessionListener です。
org.example.MySessionListener
以下の LauncherSessionListener 実装クラスでは、セッション開始時に「はじまりはじまり〜」、終了時に「おしまい」とコンソール出力するようにしました。
package org.example;
import org.junit.platform.launcher.LauncherSession;
import org.junit.platform.launcher.LauncherSessionListener;
public class MySessionListener implements LauncherSessionListener {
@Override
public void launcherSessionOpened(LauncherSession session) {
System.out.println("はじまりはじまり〜");
}
@Override
public void launcherSessionClosed(LauncherSession session) {
System.out.println("おしまい");
}
}
そして、@BeforeAll
と @AfterAll
のある単体テストクラスを2つ、結合テストクラスを1つ作成しました。ただの例なのでアサーションはありません。
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class ATest {
@BeforeAll
static void beforeAll() {
System.out.println("beforeAll at ATest");
}
@Test
void a() {
System.out.println("method A");
}
@AfterAll
static void afterAll() {
System.out.println("afterAll at ATest");
}
}
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class BTest {
@BeforeAll
static void beforeAll() {
System.out.println("beforeAll at BTest");
}
@Test
void b() {
System.out.println("method B");
}
@AfterAll
static void afterAll() {
System.out.println("afterAll at BTest");
}
}
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class MyIT {
@BeforeAll
static void beforeAll() {
System.out.println("beforeAll at MyIT");
}
@Test
void myIT() throws InterruptedException {
System.out.println("executing MyIT...");
Thread.sleep(10_000);
System.out.println("MyIT end");
}
@AfterAll
static void afterAll() {
System.out.println("afterAll at MyIT");
}
}
実行例
Maven
mvn verify
を実行すると、Surefire および Failsafe Plugin により以下のような出力が得られます。
[INFO] Scanning for projects...
[INFO]
[INFO] --------< org.example:junit-platform-launcher-session-listener >--------
[INFO] Building junit-platform-launcher-session-listener 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ junit-platform-launcher-session-listener ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory /Users/hiro/IdeaProjects/junit-platform-launcher-session-listener/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ junit-platform-launcher-session-listener ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ junit-platform-launcher-session-listener ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO]
[INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ junit-platform-launcher-session-listener ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- maven-surefire-plugin:3.0.0-M8:test (default-test) @ junit-platform-launcher-session-listener ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
はじまりはじまり〜
[INFO] Running BTest
beforeAll at BTest
method B
afterAll at BTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.016 s - in BTest
[INFO] Running ATest
beforeAll at ATest
method A
afterAll at ATest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 s - in ATest
おしまい
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ junit-platform-launcher-session-listener ---
[INFO] Building jar: /Users/hiro/IdeaProjects/junit-platform-launcher-session-listener/target/junit-platform-launcher-session-listener-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-failsafe-plugin:3.0.0-M8:integration-test (default) @ junit-platform-launcher-session-listener ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
はじまりはじまり〜
[INFO] Running MyIT
beforeAll at MyIT
executing MyIT...
MyIT end
afterAll at MyIT
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 10.036 s - in MyIT
おしまい
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO]
[INFO] --- maven-failsafe-plugin:3.0.0-M8:verify (default) @ junit-platform-launcher-session-listener ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.263 s
[INFO] Finished at: 2023-02-14T01:28:55+09:00
[INFO] ------------------------------------------------------------------------
単体テストの開始時と終了時、結合テストの開始時と終了時にそれぞれメッセージが出力されます。
Surefire Plugin で単体テストだけ実行したい場合には mvn test
を実行してください。
IntelliJ IDEA 2022.3.2
IntelliJ のコンソール出力
Maven プロジェクトとして作成し、Run 'All Tests' で実行しました。
はじまりはじまり〜
beforeAll at MyIT
executing MyIT...
MyIT end
afterAll at MyIT
beforeAll at ATest
method A
afterAll at ATest
beforeAll at BTest
method B
afterAll at BTest
おしまい
Process finished with exit code 0
テスト セッションの開始時に「はじまりはじまり〜」、終了時に「おしまい」と表示できています。Maven と違って、IT も含めて全件実行されるんですね。
IT を除外したい場合は、Run configurations の Pattern に ^(?!.*IT.*).*$
と書くと良いようです(ちょっと冗長な気も…)。先読みや後読みの正規表現は苦手なんですが、Java の String::matches
で実験してみた限りでは、(?!IT).*(?<!IT(Case)?)
で Failsafe Plugin の対象を除外できそうです。
Gradle プロジェクトの場合には、Gradle と同じクラスが対象になるようです。
画面 (Beta 版の New UI 利用)
簡単ですが、ご紹介できる内容は以上です。
繰り返しになりますが、詳細は JUnit 5 User Guide の 6.4.5. Registering a LauncherSessionListener をご覧ください。