JUnit 5は、テストの記述に使用するAPIを、テストを検出して実行する インフラストラクチャから分離しています。この分離により、Maven、IDE、 およびカスタムランチャーは、一つのインターフェイスを通じて複数の テストモデルを実行できます。
例ではJUnit 5.13.4を対象とします。JUnit 6も同じアーキテクチャを維持していますが、 JUnit 5を使い続ける必要があるプロジェクトでは、 バージョン指定されたJUnit 5ドキュメント を使用してください。
Platform、Jupiter、Vintage #
JUnit 5は三つのコンポーネントで構成されます。
| コンポーネント | 責務 |
|---|---|
| JUnit Platform | テストを検出し、登録されたテストエンジンを起動します。Maven SurefireとIDEはこのレベルで統合されます。 |
| JUnit Jupiter | JUnit 5のプログラミングモデル、拡張API、およびテストエンジンを定義します。 |
| JUnit Vintage | 移行期間中にJUnit 3およびJUnit 4のテストをPlatform上で実行します。 |
Jupiterテストは、@Test とアサーションを org.junit.jupiter.api から
インポートします。SurefireはPlatformにテストの検出を要求し、その後
junit-jupiter-engine が検出されたメソッドを実行します。テスト依存関係には
Mavenの test スコープを使用するため、アプリケーションコードはいずれの
JUnitコンポーネントにも依存しません。
最小構成のMavenプロジェクト #
次のレイアウトでは、プロダクション用クラスとテストクラスを分離します。
junit-hello/
├── pom.xml
└── src
├── main/java/com/example/Greeter.java
└── test/java/com/example/GreeterTest.java保守可能な最小構成のPOMには org.junit.jupiter:junit-jupiter を使用します。
このアーティファクトは、Jupiter API、パラメーター化テストのサポート、
およびランタイムエンジンを集約しています。
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>junit-hello</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.release>17</maven.compiler.release>
<junit.version>5.13.4</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.4</version>
</plugin>
</plugins>
</build>
</project>package com.example;
public final class Greeter {
public String greet(String name) {
if (name == null || name.isBlank()) {
throw new IllegalArgumentException("name must not be blank");
}
return "Hello, " + name;
}
}package com.example;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
class GreeterTest {
private final Greeter greeter = new Greeter();
@Test
void greetsByName() {
assertEquals("Hello, Ada", greeter.greet("Ada"));
}
@Test
void rejectsBlankNames() {
var error = assertThrows(
IllegalArgumentException.class,
() -> greeter.greet(" "));
assertEquals("name must not be blank", error.getMessage());
}
}Mavenを通じてテストを実行します。
mvn testJupiterのテストクラスとメソッドには、package-private可視性を指定できます。
テストメソッドを private または static にすることはできませんが、
ライフサイクルと拡張の規則では、特定の場所で static が許可されます。
JUnitアーティファクトの選択 #
機能が必要な場合に限り、別のアーティファクトを追加します。
| アーティファクト | 追加する場合 |
|---|---|
junit-jupiter | アプリケーションのテストスイートでは集約依存関係を優先します。API、パラメーター、およびエンジンがすでに含まれます。 |
junit-jupiter-api | ランタイムエンジンを別に管理しながら、APIに対してテストまたは拡張をコンパイルする場合。 |
junit-jupiter-engine | junit-jupiter の代わりに細分化した依存関係を使用してJupiterテストを実行する場合。テストランタイムスコープを使用します。 |
junit-jupiter-params | 細分化した設定に @ParameterizedTest のサポートを追加する場合。集約依存関係にはすでに含まれています。 |
junit-vintage-engine | 変更していないJUnit 3またはJUnit 4のテストをPlatform経由で実行する場合。 |
junit-jupiter-migrationsupport | テストをJupiterへ変換する間、一部のJUnit 4ルールと @Ignore を一時的に適応させる場合。 |
junit-platform-suite | Platformのスイートアノテーションを使用してスイートを宣言する場合。 |
junit-platform-launcher | プログラムからテストを検出して実行する場合、またはテストツールを実装する場合。アプリケーションのテストスイートが直接必要とするものではありません。 |
junit-platform-console-standalone | MavenまたはIDEの外部で、一つの実行可能JARからテストを実行する場合。このJARはプロジェクトのPOMに含めません。 |
ビルドで複数のJUnitアーティファクトを宣言する場合は、JUnit BOMを インポートしてください。BOMによってPlatform、Jupiter、およびVintageの バージョンの互換性が保たれるためです。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>BOMの対象となるアーティファクト宣言では、<version> を省略できます。
Surefire 3.0より前のリリースでは、明示的な junit-platform-launcher 依存関係が
必要でした。現在のSurefire 3.xリリースでは、テストランタイム・クラスパス上の
ランチャーがPlatformと整合するため、通常のテストスイートにランチャーを
追加してもテスト機能は増えず、管理対象のバージョンが増えるだけです。
Jupiterプログラミングモデル #
Jupiterは、一般的なテスト構造に特化したアノテーションを提供します。
@BeforeEachと@AfterEachはテストごとのフィクスチャを構築します。@BeforeAllと@AfterAllはクラスレベルのフィクスチャを構築します。@ParameterizedTestは、@ValueSource、@CsvSource、@MethodSource、 または別の引数ソースから得たデータを使い、一つのテスト本体を実行します。@Nestedは、ライフサイクルの意味を維持しながら関連するケースをまとめます。@Tagは、ビルド時に含める、または除外するテストを分類します。@ExtendWithは、パラメーター解決、コールバック、条件付き実行、および その他の横断的な振る舞いに対応する拡張を登録します。
テストでは、実行順序ではなく観測可能な結果をアサートすべきです。 Jupiterはメソッド名から自明に定まる順序を保証せず、順序付きテストは 状態を共有するため、失敗が前のケースに依存します。
JUnit 4テストを変更せずに実行する #
JupiterとJUnit 4は異なるJavaパッケージを使用し、一つのモジュール内で 共存できるため、Vintageの導入は最もリスクの低い最初の移行手順です。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>これにより、SurefireはPlatformを通じてJupiterとJUnit 4のテストを検出します。 Vintageによる実行が成功してもJupiterのプログラミングモデルや拡張モデルは 使用されないため、古いテストが残っている間だけVintageを維持してください。
JUnit 4テストの変換 #
一般的なソースコード上の対応関係は次のとおりです。
| JUnit 4 | Jupiter |
|---|---|
@Before / @After | @BeforeEach / @AfterEach |
@BeforeClass / @AfterClass | @BeforeAll / @AfterAll |
@Ignore | @Disabled |
@Category | @Tag |
@RunWith | 一つ以上の @ExtendWith 拡張 |
@Rule / @ClassRule | 拡張またはJupiterネイティブのフィクスチャ |
@Test(expected = E.class) | assertThrows(E.class, executable) |
@RunWith から @ExtendWith への移行は、機械的な名前変更ではなく、
概念上の対応付けです。JUnit 4のクラスは一つのrunnerしか持てませんが、
Jupiterは複数の拡張を組み合わせられるためです。
JUnit 4では、任意のアサーションメッセージを先頭に置きます。
assertEquals("unexpected greeting", expected, actual);Jupiterでは、メッセージを最後に置きます。
assertEquals(expected, actual, "unexpected greeting");アノテーションとライフサイクルコードをJupiterへ移行する間も、既存の
org.junit.Assert 呼び出しは残せます。アサーションを別に変換すれば、
各移行変更の規模を小さくできます。
ルールは個別に扱う必要があります。junit-jupiter-migrationsupport
アーティファクトは、ExternalResource、Verifier、ExpectedException の
ルールファミリーを適応させます。@EnableRuleMigrationSupport は、それらの
アダプターを有効にします。@EnableJUnit4MigrationSupport はJUnit 4の
@Ignore も認識します。その他のカスタムルールには、Jupiter拡張または
フィクスチャの直接的な書き換えが必要です。
したがって、管理された移行は次の三段階で進めます。
- Vintageを追加し、Platformベースのテストコマンドを一つ確立する。
- 名前ではなく振る舞いに基づいてrunnerとルールを置き換えながら、 クラスをJupiterへ変換する。
- ビルド内にJUnit 3またはJUnit 4のテストがなくなった後、Vintage、JUnit 4、 および移行サポートを削除する。
コメント
GitHub で閲覧・コメントする(投稿にはログインが必要です)