1. 概要
この文書は、テストを書くプログラマーや拡張機能の作者、ビルドツールやIDEを含むテストエンジンの作者に対して、 包括的なリファレンスを提供することを目的としています。
Translations
|
1.1. JUnit 5とは
これまでのバージョンのJUnitとは異なり、JUnit 5は 3つのサブプロジェクトに含まれる複数のモジュールで構成されます。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit Platform は、JVM上で テストフレームワークを起動する
ための基盤となり、このプラットフォーム上で動作するテストフレームワークを開発するための
TestEngine
APIを定義しています。加えて、コマンドラインからプラットフォームを起動するための
Console Launcher や、
Gradle と Maven
用のビルドプラグイン、 JUnit 4ベースのテストランナー
などを提供し、あらゆる TestEngine
を実行できるようになっています。
JUnit Jupiter は、JUnit 5でテストや拡張機能を書くための新しい
プログラミングモデル と 拡張モデル の組み合わせです。
Jupiterサブプロジェクトは、プラットフォーム上でJupiterベースのテストを実行するための
TestEngine
を提供します。
JUnit Vintage は、プラットフォーム上でJUnit 3またはJUnit 4
ベースのテストを実行するための TestEngine
を提供します。
1.2. サポートされるJavaバージョン
JUnit 5を実行するには、Java 8(またはそれ以上)が必要となります。 ただし、それより古いバージョンのJDKでコンパイルされたコードをテストすることは可能です。
1.3. 助けてもらうには
Stack Overflow で質問するか、 Gitter で私たちにチャットしてください。
2. インストール
最終リリースや各マイルストーンでの成果物は、Maven Centralリポジトリにデプロイされています。
スナップショットは、Sonatype スナップショットリポジトリ の /org/junit 以下にデプロイされています。
2.1. 依存関係メタデータ
2.1.1. JUnit Platform
-
Group ID:
org.junit.platform
-
Version:
1.3.0
-
Artifact IDs:
junit-platform-commons
-
JUnitの内部的な共通ライブラリ/ユーティリティです。これらのユーティリティは、 JUnitフレームワーク自身で使われることだけを想定しています。 外部のプログラムからの利用はサポートされていません。 利用は自己責任で!
junit-platform-console
-
コンソールからJUnit Platform上でテストを見つけて実行する機能を提供します。 詳細は、 Console Launcher を参照してください。
junit-platform-console-standalone
-
すべての依存関係を含む実行可能なJARは、Maven Centralリポジトリの junit-platform-console-standalone ディレクトリで提供されています。詳細は、 Console Launcher を参照してください。
junit-platform-engine
-
テストエンジンの公開APIです。詳細は、 Plugging in your own Test Engine を参照してください。
junit-platform-launcher
-
テストプランを構成して起動するための公開APIです。通常は、IDEやビルドツールに使われます。 詳細は、 JUnit Platform Launcher API を参照してください。
junit-platform-runner
-
JUnit Platform上のテストおよびテストスイートをJUnit 4環境で実行するテストランナーです。 詳細は、 JUnit Platformの実行にJUnit 4を使う を参照してください。
junit-platform-suite-api
-
JUnit Platform上でテストスイートを構成するためのアノテーションです。 JUnitPlatformランナー と(おそらく)サードパーティーの
TestEngine
実装にもサポートされます。 junit-platform-surefire-provider
-
Maven Surefire を使って、 JUnit Platform上でテストを見つけて実行する機能を提供します。
2.1.2. JUnit Jupiter
-
Group ID:
org.junit.jupiter
-
Version:
5.3.0
-
Artifact IDs:
junit-jupiter-api
junit-jupiter-engine
-
JUnit Jupiterのテストエンジン実装です。実行時だけ必要になります。
junit-jupiter-params
-
JUnit Jupiterで パラメーター化テスト をサポートします。
junit-jupiter-migrationsupport
-
JUnit 4からJUnit Jupiterへの移行をサポートします。 JUnit Jupiter上で、JUnit 4ルールを実行したいときだけ必要になります。
2.1.3. JUnit Vintage
-
Group ID:
org.junit.vintage
-
Version:
5.3.0
-
Artifact ID:
junit-vintage-engine
-
JUnit Vintageのテストエンジン実装です。JUnit 3またはJUnit 4で書かれた昔のテストを 新しいJUnit Platform上で実行できるようにします。
2.3. JUnit Jupiterサンプルプロジェクト
junit5-samples
リポジトリは、
JUnit JupiterベースとJUnit Vintageベースのプロジェクトの様々なサンプルを提供します。
以下のプロジェクトでビルドスクリプト(例えば、build.gradle
や pom.xml
など)
を見つけられるでしょう。
-
GradleとJavaの場合は、
junit5-jupiter-starter-gradle
プロジェクトを参照してください -
GradleとKotlinの場合は、
junit5-jupiter-starter-gradle-kotlin
プロジェクトを参照してください -
GradleとGroovyの場合は、
junit5-jupiter-starter-gradle-groovy
プロジェクトを参照してください -
Mavenの場合は、
junit5-jupiter-starter-maven
プロジェクトを参照してください -
Antの場合は、
junit5-jupiter-starter-ant
プロジェクトを参照してください
3. テストを書く
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class FirstJUnit5Tests {
@Test
void myFirstTest() {
assertEquals(2, 1 + 1);
}
}
3.1. アノテーション
JUnit Jupiterは、テストを構成し、フレームワークを拡張するために、次のアノテーションをサポートします。
中心となるすべてのアノテーションは、 junit-jupiter-api
モジュールの org.junit.jupiter.api
パッケージに含まれます。
アノテーション | 説明 |
---|---|
|
このメソッドが、テストメソッドであることを示します。JUnit 4の |
|
このメソッドが、パラメーター化テスト であることを示します。このメソッドは、オーバーライド されない限り、継承 されます。 |
|
このメソッドが、繰り返しテスト のためのテストテンプレートであることを示します。このメソッドは、オーバーライド されない限り、継承 されます。 |
|
このメソッドが、動的テスト のためのテストファクトリであることを示します。このメソッドは、オーバーライド されない限り、継承 されます。 |
|
アノテーションを付与したテストクラスに対して、テストインスタンスのライフサイクル を設定するために使われます。このアノテーションは、継承 されます。 |
|
このメソッドが、テストケースのテンプレート であることを示します。このメソッドは、登録した プロバイダ が返す実行コンテキストの数に応じて、複数回呼び出されます。このメソッドは、オーバーライド されない限り、継承 されます。 |
|
テストクラスやテストメソッドにカスタムの表示名を指定します。このアノテーションは、継承 されません。 |
|
このメソッドが、現在のクラスの |
|
このメソッドが、現在のクラスの |
|
このメソッドが、現在のクラスの すべての |
|
このメソッドが、現在のクラスの すべての |
|
このクラスが、ネストした非staticのテストクラスであることを示します。 |
|
クラスまたはメソッドレベルでテストをフィルタリングするための タグ を宣言するのに使われます。TestNGのテストグループやJUnit 4のCategoryと同じです。このアノテーションは、クラスレベルでは 継承 されますが、メソッドレベルでは 継承 されません。 |
|
テストクラスやテストメソッドを 無効化 するのに使われます。JUnit 4の |
|
カスタムの 拡張機能 を登録するために使われます。このアノテーションは、継承 されます。 |
@Test
, @TestTemplate
, @RepeatedTest
, @BeforeAll
, @AfterAll
, @BeforeEach
, @AfterEach
アノテーションの付与されたメソッドは、戻り値を返してはいけません。
いくつかのアノテーションは現在 実験中 です。詳細は、 実験的なAPI のテーブルを参照してください。 |
3.1.1. メタアノテーションと合成アノテーション
JUnit Jupiterアノテーションは、メタアノテーション として使うことができます。つまり、 メタアノテーションの意味を自動的に 継承 した独自の 合成アノテーション を作れるということです。
例えば、@Tag("fast")
をコードベース全体にコピー&ペーストする代わりに
(タグとフィルタリング 参照)、以下の @Fast
のような名前のカスタム 合成アノテーション を作ることができます。
@Fast
は、@Tag("fast")
の代わりに使うことができます。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
public @interface Fast {
}
3.2. テストクラスとテストメソッド
テストメソッド (test method) とは、@Test
, @RepeatedTest
, @ParameterizedTest
,
@TestFactory
, @TestTemplate
のいずれかが直接またはメタアノテーションとして付与された
インスタンスメソッドです。テストクラス (test class) とは、テストメソッドを少なくとも1つもつ
トップレベルまたはstaticな内部クラスです。
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
class StandardTests {
@BeforeAll
static void initAll() {
}
@BeforeEach
void init() {
}
@Test
void succeedingTest() {
}
@Test
void failingTest() {
fail("失敗するテスト");
}
@Test
@Disabled("デモ用")
void skippedTest() {
// 実行されない
}
@AfterEach
void tearDown() {
}
@AfterAll
static void tearDownAll() {
}
}
テストクラスやテストメソッドは、 public である必要がありません。
|
3.3. 表示名
テストクラスやテストメソッドは、カスタムの表示名を宣言できます。 空白や特殊文字だけでなく絵文字も含めることができ、テストランナーやテストレポートに表示されます。
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("特殊なテストケース")
class DisplayNameDemo {
@Test
@DisplayName("スペースを 含む カスタムの テスト名")
void testWithDisplayNameContainingSpaces() {
}
@Test
@DisplayName("╯°□°)╯")
void testWithDisplayNameContainingSpecialCharacters() {
}
@Test
@DisplayName("😱")
void testWithDisplayNameContainingEmoji() {
}
}
3.4. アサーション
JUnit Jupiterは、JUnit 4にあった多くのアサーションメソッドをもち、
Java 8のラムダ式と一緒に使いやすいものもいくつか追加しています。
すべてのJUnit Jupiterアサーションは、 org.junit.jupiter.api.Assertions
クラスの static
メソッドです。
import static java.time.Duration.ofMillis;
import static java.time.Duration.ofMinutes;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTimeout;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
class AssertionsDemo {
@Test
void standardAssertions() {
assertEquals(2, 2);
assertEquals(4, 4, "省略可能なアサーションメッセージは最後のパラメーター");
assertTrue('a' < 'b', () -> "アサーションメッセージは遅延評価できる -- "
+ "不必要に複雑なメッセージを構築するコストを割けるために");
}
@Test
void groupedAssertions() {
// アサーションをグループ化すると、すべてのアサーションが一度に実行され、
// すべての失敗がまとめて報告される。
assertAll("person",
() -> assertEquals("John", person.getFirstName()),
() -> assertEquals("Doe", person.getLastName())
);
}
@Test
void dependentAssertions() {
// コードブロック内でアサーションが失敗すると、同じブロック内の後続のコードはスキップされる。
assertAll("properties",
() -> {
String firstName = person.getFirstName();
assertNotNull(firstName);
// 上のアサーションが成功した場合のみ実行される。
assertAll("first name",
() -> assertTrue(firstName.startsWith("J")),
() -> assertTrue(firstName.endsWith("n"))
);
},
() -> {
// グループ化されたアサーションは、first name のアサーションとは独立して実行される。
String lastName = person.getLastName();
assertNotNull(lastName);
// 上のアサーションが成功した場合のみ実行される。
assertAll("last name",
() -> assertTrue(lastName.startsWith("D")),
() -> assertTrue(lastName.endsWith("e"))
);
}
);
}
@Test
void exceptionTesting() {
Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");
});
assertEquals("a message", exception.getMessage());
}
@Test
void timeoutNotExceeded() {
// 次のアサーションは成功する。
assertTimeout(ofMinutes(2), () -> {
// 2分未満で終わるタスクを実行する。
});
}
@Test
void timeoutNotExceededWithResult() {
// 次のアサーションは成功し、指定されたオブジェクトを返す。
String actualResult = assertTimeout(ofMinutes(2), () -> {
return "a result";
});
assertEquals("a result", actualResult);
}
@Test
void timeoutNotExceededWithMethod() {
// 次のアサーションは、メソッド参照を実行してオブジェクトを返す。
String actualGreeting = assertTimeout(ofMinutes(2), AssertionsDemo::greeting);
assertEquals("Hello, World!", actualGreeting);
}
@Test
void timeoutExceeded() {
// 次のアサーションは、以下のようなエラーメッセージを出して失敗する:
// execution exceeded timeout of 10 ms by 91 ms
assertTimeout(ofMillis(10), () -> {
// 10ミリ秒より時間のかかるタスクをシミュレートする。
Thread.sleep(100);
});
}
@Test
void timeoutExceededWithPreemptiveTermination() {
// 次のアサーションは、以下のようなエラーメッセージを出して失敗する:
// execution timed out after 10 ms
assertTimeoutPreemptively(ofMillis(10), () -> {
// 10ミリ秒より時間のかかるタスクをシミュレートする。
Thread.sleep(100);
});
}
private static String greeting() {
return "Hello, World!";
}
}
JUnit Jupiterは、 Kotlin
と一緒に使いやすいアサーションもいくつか含んでいます。すべてのJUnit Jupiter Kotlinアサーションは、
org.junit.jupiter.api
パッケージのトップレベル関数です。
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.assertThrows
class AssertionsKotlinDemo {
@Test
fun `grouped assertions`() {
assertAll("person",
{ assertEquals("John", person.firstName) },
{ assertEquals("Doe", person.lastName) }
)
}
@Test
fun `exception testing`() {
val exception = assertThrows<IllegalArgumentException> ("Should throw an exception") {
throw IllegalArgumentException("a message")
}
assertEquals("a message", exception.message)
}
@Test
fun `assertions from a stream`() {
assertAll(
"people with name starting with J",
people
.stream()
.map {
// This mapping returns Stream<() -> Unit>
{ assertTrue(it.firstName.startsWith("J")) }
}
)
}
@Test
fun `assertions from a collection`() {
assertAll(
"people with last name of Doe",
people.map { { assertEquals("Doe", it.lastName) } }
)
}
}
3.4.1. サードパーティーのアサーションライブラリ
多くのテストシナリオではJUnit Jupiterが提供するアサーション機能だけで十分ですが、 時にはさらなるパワーや マッチャー のような追加機能が必要になることもあります。 そのような場合には、 AssertJ や Hamcrest、 Truth のようなサードパーティーの アサーションライブラリを使うことをJUnitチームはお勧めします。 開発者は、好みに応じてアサーションライブラリを自由に選択することができます。
例えば、 マッチャー と流れるようなAPIを組み合わせれば、アサーションをもっと説明的で
読みやすくすることができます。しかし、JUnit Jupiterの org.junit.jupiter.api.Assertions
クラスは、
JUnit 4の org.junit.Assert
クラスのようにHamcrestの
Matcher
を受け付ける
assertThat()
メソッドを提供していません。代わりに、開発者はサードパーティーのアサーションライブラリが
提供するマッチャーを利用することが推奨されます。
次の例は、JUnit JupiterテストでHamcrestの assertThat()
を使う方法を示しています。
Hamcrestライブラリをクラスパスに追加しさえすれば、 assertThat()
や is()
、 equalTo()
のようなメソッドをstatic importして、下の assertWithHamcrestMatcher()
メソッドのように
テストの中で使うことができます。
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.jupiter.api.Test;
class HamcrestAssertionDemo {
@Test
void assertWithHamcrestMatcher() {
assertThat(2 + 1, is(equalTo(3)));
}
}
当然ながら、JUnit 4のプログラミングモデルに基づくレガシーなテストでは、引き続き
org.junit.Assert#assertThat
を使い続けることができます。
3.5. 前提条件
JUnit Jupiterは、JUnit 4が提供する前提条件用メソッドの一部を備え、
Java 8のラムダ式と一緒に使いやすいものをいくつか追加しています。
JUnit Jupiterの前提条件メソッドは、すべて org.junit.jupiter.api.Assumptions
クラスのstaticメソッドです。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.junit.jupiter.api.Assumptions.assumingThat;
import org.junit.jupiter.api.Test;
class AssumptionsDemo {
@Test
void testOnlyOnCiServer() {
assumeTrue("CI".equals(System.getenv("ENV")));
// 残りのテスト
}
@Test
void testOnlyOnDeveloperWorkstation() {
assumeTrue("DEV".equals(System.getenv("ENV")),
() -> "テストを中断: 開発者マシンではない");
// 残りのテスト
}
@Test
void testInAllEnvironments() {
assumingThat("CI".equals(System.getenv("ENV")),
() -> {
// これらのアサーションはCIサーバーでのみ実行する
assertEquals(2, 2);
});
// これらのアサーションはすべての環境で実行する
assertEquals("a string", "a string");
}
}
3.6. テストの無効化
テストクラス全体または個々のテストメソッドは、 @Disabled
アノテーションや
条件付きテスト実行 で説明するアノテーション、
あるいはカスタムの ExecutionCondition
によって 無効化 することができます。
次の例は、@Disabled
されたテストクラスです。
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled
class DisabledClassDemo {
@Test
void testWillBeSkipped() {
}
}
そして次の例は、@Disabled
されたテストメソッドをもつテストクラスです。
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
class DisabledTestsDemo {
@Disabled
@Test
void testWillBeSkipped() {
}
@Test
void testWillBeExecuted() {
}
}
3.7. 条件付きテスト実行
JUnit Jupiterの ExecutionCondition
拡張APIは、
開発者がある一定の条件にもとづいて 手続き的に コンテナやテストを有効化したり、
無効化したりすることができるようにします。
簡単な例は、@Disabled
アノテーションをサポートする DisabledCondition
です
(テストの無効化 参照)。
JUnit Jupiterは、org.junit.jupiter.api.condition
パッケージで @Disabled
以外にもアノテーションベースの条件をサポートしています。これにより、開発者は 宣言的に
コンテナやテストを有効化したり、無効化したりすることができます。
詳細は、以降の節を参照してください。
合成アノテーション
以降で説明するいずれの 条件 アノテーションも、カスタムの 合成アノテーション
を作るためのメタアノテーションとして使われうる点に注意してください。例えば、
@EnabledOnOsデモ の |
以降の節で取り上げられる 条件 アノテーションは、あるテストインターフェースやテストクラス、
テストメソッドに対して一度しか宣言できません。条件アノテーションがある要素に対して直接、
間接、あるいはメタアノテーションで複数回指定されたとしても、JUnitが最初に見つけた
アノテーションだけが使われます。その他のアノテーションは、黙って無視されます。ただし、
|
3.7.1. オペレーティングシステム条件
@EnabledOnOs
および @DisabledOnOs
アノテーションを使うと、
コンテナやテストを特定のオペレーティングシステムで有効にしたり無効にしたりできます。
@Test
@EnabledOnOs(MAC)
void onlyOnMacOs() {
// ...
}
@TestOnMac
void testOnMac() {
// ...
}
@Test
@EnabledOnOs({ LINUX, MAC })
void onLinuxOrMac() {
// ...
}
@Test
@DisabledOnOs(WINDOWS)
void notOnWindows() {
// ...
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@EnabledOnOs(MAC)
@interface TestOnMac {
}
3.7.2. Javaランタイム環境条件
@EnabledOnJre
および @DisabledOnJre
アノテーションを使うと、
コンテナやテストを特定のバージョンのJavaランタイム環境(JRE)で有効にしたり無効にしたりできます。
@Test
@EnabledOnJre(JAVA_8)
void onlyOnJava8() {
// ...
}
@Test
@EnabledOnJre({ JAVA_9, JAVA_10 })
void onJava9Or10() {
// ...
}
@Test
@DisabledOnJre(JAVA_9)
void notOnJava9() {
// ...
}
3.7.3. システムプロパティ条件
@EnabledIfSystemProperty
および @DisabledIfSystemProperty
アノテーションを使うと、
指定した名前をもつJVMシステムプロパティの値に応じて、コンテナやテストを有効にしたり
無効にしたりできます。 matches
属性で指定する値は、正規表現として解釈されます。
@Test
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
void onlyOn64BitArchitectures() {
// ...
}
@Test
@DisabledIfSystemProperty(named = "ci-server", matches = "true")
void notOnCiServer() {
// ...
}
3.7.4. 環境変数条件
@EnabledIfEnvironmentVariable
および @DisabledIfEnvironmentVariable
アノテーションを使うと、指定した名前をもつ環境変数の値に応じて、コンテナやテストを
有効にしたり無効にしたりできます。matches
属性で指定する値は、正規表現として解釈されます。
@Test
@EnabledIfEnvironmentVariable(named = "ENV", matches = "staging-server")
void onlyOnStagingServer() {
// ...
}
@Test
@DisabledIfEnvironmentVariable(named = "ENV", matches = ".*development.*")
void notOnDeveloperWorkstation() {
// ...
}
3.7.5. スクリプトベースの条件
JUnit Jupiterは、@EnabledIf
または @DisabledIf
アノテーションで設定された
スクリプトの実行結果に応じて、コンテナやテストを有効にしたり無効にしたりする機能を提供します。
スクリプトは、JavaScript、Groovy、あるいはJSR 223で定義されたJava Scripting API
をサポートする任意の言語で記述することができます。
@EnabledIf および @DisabledIf を使った条件付きテスト実行は、
現在 試験的な 機能です。詳細は、実験的なAPI
のテーブルを参考にしてください。
|
もしスクリプトのロジックが現在のオペレーティングシステムやJavaランタイム環境の バージョン、特定のJVMシステムプロパティや環境変数だけに依存するなら、その目的専用の 組み込みアノテーションの使用を検討すべきです。詳細は、この章の前の節を参照してください。 |
もし同じようなスクリプトベースの条件を何回も使っていると感じたら、 高速かつタイプセーフで、よりメンテナンスしやすい方法で実装するために、専用の ExecutionCondition 拡張を書くことを検討してください。 |
@Test // 静的なJavaScriptの式
@EnabledIf("2 * 3 == 6")
void willBeExecuted() {
// ...
}
@RepeatedTest(10) // 動的なJavaScriptの式
@DisabledIf("Math.random() < 0.214159")
void mightNotBeExecuted() {
// ...
}
@Test // システムプロパティをテストする正規表現
@DisabledIf("/32/.test(systemProperty.get('os.arch'))")
void disabledOn32BitArchitectures() {
assertFalse(System.getProperty("os.arch").contains("32"));
}
@Test
@EnabledIf("'CI' == systemEnvironment.get('ENV')")
void onlyOnCiServer() {
assertTrue("CI".equals(System.getenv("ENV")));
}
@Test // 複数行のスクリプト、カスタムのエンジン名、カスタムの理由(訳注:テストが無効化された場合に表示される)
@EnabledIf(value = {
"load('nashorn:mozilla_compat.js')",
"importPackage(java.time)",
"",
"var today = LocalDate.now()",
"var tomorrow = today.plusDays(1)",
"tomorrow.isAfter(today)"
},
engine = "nashorn",
reason = "Self-fulfilling: {result}")
void theDayAfterTomorrow() {
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
assertTrue(tomorrow.isAfter(today));
}
スクリプトバインディング
以下の名前は、スクリプトのコンテキストに束縛されるため、スクリプト内で使うことができます。
accessor は、単純な String get(String name)
メソッドを介したマップ構造への
アクセスを提供します。
Name | Type | Description |
---|---|---|
|
accessor |
オペレーティングシステムの環境変数へのアクセッサ |
|
accessor |
JVMのシステムプロパティへのアクセッサ |
|
accessor |
設定パラメーターへのアクセッサ |
|
|
テストやコンテナの表示名 |
|
|
テストやコンテナにアサインされたすべてのタグ |
|
|
テストやコンテナの一意なID |
3.8. タグとフィルタリング
テストクラスとテストメソッドには、@Tag
アノテーションでタグを付与することができます。
これらのタグはあとで テストを発見・実行 するときのフィルタリングに
使うことができます。
3.8.1. タグの構文規則
-
タグは、
null
または 空 であってはならない -
トリミングした タグは、空白文字を含んではならない
-
トリミングした タグは、ISO制御文字を含んではならない
-
トリミングした タグは、次の 予約済み文字 を含んではならない
-
,
: カンマ -
(
: 左括弧 -
)
: 右括弧 -
&
: アンパサンド -
|
: 縦棒 -
!
: 感嘆符
-
上のコンテキストで "トリミングした" とは、先頭および末尾の空白文字が 取り除かれていることを意味する。 |
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@Tag("fast")
@Tag("model")
class TaggingDemo {
@Test
@Tag("taxes")
void testingTaxCalculation() {
}
}
3.9. テストインスタンスのライフサイクル
個々のテストメソッドを隔離された環境で実行し、 テストインスタンスをミュータブルにすると起こりうる意図しない副作用を避けるため、 JUnitは テストメソッド (テストクラスとテストメソッド 参照) 毎にそのテストクラスの新しいインスタンスを生成して実行します。 この "per-method(メソッド毎)" のテストインスタンスライフサイクルは、JUnit Jupiter のデフォルトの挙動で、過去のJUnitのバージョンと同じです。
"per-method" のテストインスタンスライフサイクルモードが有効であったとしても、
条件 (例えば、@Disabled や
@DisabledOnOs など)によって テストメソッド が 無効化 されている場合は、
テストクラスのインスタンスが作り直されない点に注意してください。
|
もしすべてのテストメソッドを同じテストインスタンスで実行させたい場合は、テストクラスに
@TestInstance(Lifecycle.PER_CLASS)
アノテーションを付与してください。
このモードを使うと、新しいテストインスタンスはテストクラス毎に1回だけ生成されます。
そのため、もしテストメソッドがインスタンス変数の状態に依存するのであれば、
@BeforeEach
や @AfterEach
メソッドで状態をリセットする必要があります。
"per-class(クラス毎)" モードは、デフォルトの "per-method(メソッド毎)" モードに比べて
追加のメリットがあります。具体的には、"per-class" モードでは @BeforeAll
および
@AfterAll
をインターフェースの default
メソッドやクラスの非staticなメソッドに
対して宣言できるようになります。そのため、"per-class" モードでは @BeforeAll
や
@AfterAll
メソッドを @Nested
テストクラスでも使えます。
もしプログラミング言語Kotlinでテストを書く場合は、テストインスタンスのライフサイクルを
"per-class" モードに切り替えると、@BeforeAll
および @AfterAll
メソッドを
より実装しやすいでしょう。
3.9.1. テストインスタンスのデフォルトのライフサイクルの変更
テストクラスやテストインターフェースに @TestInstance
アノテーションを付与すると、
JUnit Jupiterは デフォルト のライフサイクルモードを使います。標準の デフォルト
モードは PER_METHOD
ですが、テストプラン全体で デフォルト を変更することもできます。
テストインスタンスのデフォルトのライフサイクルモードを変更するには、単に
junit.jupiter.testinstance.lifecycle.default
設定パラメーター に
TestInstance.Lifecycle
で定義された列挙定数を指定するだけです。
これは、JVMシステムプロパティや Launcher
に渡される LauncherDiscoveryRequest
の 設定パラメーター 、あるいはJUnit Platform設定ファイルなどで指定できます
(詳細は、設定パラメーター 参照)。
例えば、デフォルトのライフサイクルモードを Lifecycle.PER_CLASS
に設定するには、
次のシステムプロパティを指定してJVMを起動します。
-Djunit.jupiter.testinstance.lifecycle.default=per_class
ただし、デフォルトのライフサイクルモードをJUnit Platform設定ファイルで指定する方が、 よりロバストである点に注意してください。というのも、設定ファイルならプロジェクトの バージョン管理システムにチェックインでき、IDEやビルドツールからも使えるからです。
JUnit Platform設定ファイルを使ってデフォルトのライフサイクルモードを Lifecycle.PER_CLASS
にするには、クラスパスのルート(例えば、src/test/resources
)に junit-platform.properties
という名前で次のファイルを作ります。
junit.jupiter.testinstance.lifecycle.default = per_class
テストインスタンスの デフォルト のライフサイクルモードを変更する場合は、 一貫性のある方法で適用しないと予測できない結果や不安定なビルドにつながる可能性があります。 例えば、ビルドでは "per-class" をデフォルトとして設定していても、IDEが "per-method" でテストを実行していると、ビルドサーバーで起きたエラーをデバッグするのが難しくなります。 そのため、JVMシステムプロパティの代わりにJUnit Platform設定ファイルを使って デフォルトを変更することをお勧めします。 |
3.10. ネストしたテスト
ネストしたテストは、テスト作成者がテストのグループ関係を表現しやすくします。 詳しい例は次の通りです。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.EmptyStackException;
import java.util.Stack;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@DisplayName("A stack")
class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("is instantiated with new Stack()")
void isInstantiatedWithNew() {
new Stack<>();
}
@Nested
@DisplayName("when new")
class WhenNew {
@BeforeEach
void createNewStack() {
stack = new Stack<>();
}
@Test
@DisplayName("is empty")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("throws EmptyStackException when popped")
void throwsExceptionWhenPopped() {
assertThrows(EmptyStackException.class, () -> stack.pop());
}
@Test
@DisplayName("throws EmptyStackException when peeked")
void throwsExceptionWhenPeeked() {
assertThrows(EmptyStackException.class, () -> stack.peek());
}
@Nested
@DisplayName("after pushing an element")
class AfterPushing {
String anElement = "an element";
@BeforeEach
void pushAnElement() {
stack.push(anElement);
}
@Test
@DisplayName("it is no longer empty")
void isNotEmpty() {
assertFalse(stack.isEmpty());
}
@Test
@DisplayName("returns the element when popped and is empty")
void returnElementWhenPopped() {
assertEquals(anElement, stack.pop());
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("returns the element when peeked but remains not empty")
void returnElementWhenPeeked() {
assertEquals(anElement, stack.peek());
assertFalse(stack.isEmpty());
}
}
}
}
非staticなネストクラス(すなわち、内部クラス)だけが、@Nested
テストクラスとして使えます。ネストの深さは自由で、すべての内部クラスがテストクラスの
一部とみなされます。ただし、1つだけ例外があり、@BeforeAll および @AfterAll
メソッドは、デフォルトでは 機能しません。というのも、Javaでは内部クラスで
static メンバーを使用できないからです。しかし、この制限は @Nested テストクラスに
@TestInstance(Lifecycle.PER_CLASS) アノテーションを付与することで回避できます
( テストインスタンスのライフサイクル 参照)。
|
3.11. コンストラクタとメソッドへの依存性注入
これまでのバージョンのJUnitでは、テストクラスのコンストラクタとメソッドは
(少なくとも標準の Runner
実装では)引数をもつことができませんでした。
JUnit Jupiterの大きな変更点の1つは、テストのコンストラクタやメソッドが
引数をもてるようになったことです。これは大きな柔軟性をもたらし、
依存性注入 を可能にします。
ParameterResolver
は、実行時に 動的に 引数を解決したいテスト拡張のための
APIを定義しています。もしテストコンストラクタや @Test
, @TestFactory
,
@BeforeEach
, @AfterEach
, @BeforeAll
, @AfterAll
メソッドが引数をもつ場合、
その引数は登録済みの ParameterResolver
によって解決されます。
現状、自動的に登録される組み込みのResolverが3つあります。
-
TestInfoParameterResolver
: もしメソッドの引数の型がTestInfo
の場合、TestInfoParameterResolver
が現在のテストに応じたTestInfo
をその引数の値として 与えます。TestInfo
は、テストの表示名やテストクラス、テストメソッド、付与されたタグなど、 現在のテストに関する情報を取得するために使用できます。表示名は、テストクラスやテストメソッド の名前か、@DisplayName
で設定されたカスタムの名前か、どちらかになります。TestInfo
は、JUnit 4のTestName
ルールの代替として使えます。 次の例は、TestInfo
をテストのコンストラクタ、@BeforeEach
メソッド、および@Test
メソッドに注入する方法を示しています。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
@DisplayName("TestInfo Demo")
class TestInfoDemo {
TestInfoDemo(TestInfo testInfo) {
assertEquals("TestInfo Demo", testInfo.getDisplayName());
}
@BeforeEach
void init(TestInfo testInfo) {
String displayName = testInfo.getDisplayName();
assertTrue(displayName.equals("TEST 1") || displayName.equals("test2()"));
}
@Test
@DisplayName("TEST 1")
@Tag("my-tag")
void test1(TestInfo testInfo) {
assertEquals("TEST 1", testInfo.getDisplayName());
assertTrue(testInfo.getTags().contains("my-tag"));
}
@Test
void test2() {
}
}
-
RepetitionInfoParameterResolver
: もし@RepeatedTest
,@BeforeEach
,@AfterEach
メソッドの引数の型がRepetitionInfo
の場合、RepetitionInfoParameterResolver
がRepetitionInfo
インスタンスを与えます。RepetitionInfo
は、@RepeatedTest
の現在の繰り返し回数や合計回数の情報を 取得するために使用できます。ただし、RepetitionInfoParameterResolver
は@RepeatedTest
以外では登録されないことに注意してください。 繰り返しテストの例 を参照。 -
TestReporterParameterResolver
: もしメソッドの引数の型がTestReporter
の場合、TestReporterParameterResolver
がTestReporter
インスタンスを与えます。TestReporter
は、現在のテスト実行に関する追加のデータを出力するために使用できます。 このデータは、TestExecutionListener.reportingEntryPublished()
を通して取得できるので、IDEで参照したり、レポートに含めたりできます。JUnit Jupiterでは、JUnit 4で
stdout
やstderr
に情報を出力していた代わりに、TestReporter
を使うべきです。@RunWith(JUnitPlatform.class)
を使うときも、 すべてのレポート情報がstdout
に出力されます。
class TestReporterDemo {
@Test
void reportSingleValue(TestReporter testReporter) {
testReporter.publishEntry("a status message");
}
@Test
void reportKeyValuePair(TestReporter testReporter) {
testReporter.publishEntry("a key", "a value");
}
@Test
void reportMultipleKeyValuePairs(TestReporter testReporter) {
testReporter.publishEntry(
Map.of(
"user name", "dk38",
"award year", "1974"
));
}
}
そのほかの ParameterResolver は、@ExtendWith を使って適切な
拡張機能 を登録することで、明示的に有効にしなければなりません。
|
カスタムの ParameterResolver
のサンプルとしては、RandomParametersExtension
を参照してください。本番利用を想定したものではありませんが、
拡張モデルとパラメーター解決処理のシンプルさや高い表現力を示しています。
MyRandomParametersTest
は、乱数を @Test
メソッドに注入する例になっています。
@ExtendWith(RandomParametersExtension.class)
class MyRandomParametersTest {
@Test
void injectsInteger(@Random int i, @Random int j) {
assertNotEquals(i, j);
}
@Test
void injectsDouble(@Random double d) {
assertEquals(0.0, d, 1.0);
}
}
実世界のユースケースとしては、MockitoExtension
や SpringExtension
のソースコードを確認してください。
3.12. テストインターフェースとデフォルトメソッド
JUnit Jupiterでは、@Test
, @RepeatedTest
, @ParameterizedTest
, @TestFactory
,
@TestTemplate
, @BeforeEach
, @AfterEach
アノテーションをインターフェースの
default
メソッドに対して宣言することもできます。 @BeforeAll
と @AfterAll
はテストインターフェースの static
メソッドにしか宣言できませんが、
@TestInstance(Lifecycle.PER_CLASS)
がテストインターフェースまたはテストクラスに
付与されていればインターフェースの default
メソッドに宣言することもできます
(テストインスタンスのライフサイクル 参照)。以下はサンプルです。
@TestInstance(Lifecycle.PER_CLASS)
interface TestLifecycleLogger {
static final Logger LOG = Logger.getLogger(TestLifecycleLogger.class.getName());
@BeforeAll
default void beforeAllTests() {
LOG.info("Before all tests");
}
@AfterAll
default void afterAllTests() {
LOG.info("After all tests");
}
@BeforeEach
default void beforeEachTest(TestInfo testInfo) {
LOG.info(() -> String.format("About to execute [%s]",
testInfo.getDisplayName()));
}
@AfterEach
default void afterEachTest(TestInfo testInfo) {
LOG.info(() -> String.format("Finished executing [%s]",
testInfo.getDisplayName()));
}
}
interface TestInterfaceDynamicTestsDemo {
@TestFactory
default Collection<DynamicTest> dynamicTestsFromCollection() {
return Arrays.asList(
dynamicTest("1st dynamic test in test interface", () -> assertTrue(true)),
dynamicTest("2nd dynamic test in test interface", () -> assertEquals(4, 2 * 2))
);
}
}
@ExtendWith
と @Tag
はテストインターフェースに宣言することで、
そのインタフェースを実装したクラスにタグと拡張機能を自動的に継承させることができます。
テスト実行前後のコールバック にある
TimingExtension
のソースコードを参照してください。
@Tag("timed")
@ExtendWith(TimingExtension.class)
interface TimeExecutionLogger {
}
これらのインタフェースを実装することでテストクラスに適用することができます。
class TestInterfaceDemo implements TestLifecycleLogger,
TimeExecutionLogger, TestInterfaceDynamicTestsDemo {
@Test
void isEqualValue() {
assertEquals(1, 1, "is always equal");
}
}
TestInterfaceDemo
を実行すると、次のような出力となります。
:junitPlatformTest INFO example.TestLifecycleLogger - Before all tests INFO example.TestLifecycleLogger - About to execute [dynamicTestsFromCollection()] INFO example.TimingExtension - Method [dynamicTestsFromCollection] took 13 ms. INFO example.TestLifecycleLogger - Finished executing [dynamicTestsFromCollection()] INFO example.TestLifecycleLogger - About to execute [isEqualValue()] INFO example.TimingExtension - Method [isEqualValue] took 1 ms. INFO example.TestLifecycleLogger - Finished executing [isEqualValue()] INFO example.TestLifecycleLogger - After all tests Test run finished after 190 ms [ 3 containers found ] [ 0 containers skipped ] [ 3 containers started ] [ 0 containers aborted ] [ 3 containers successful ] [ 0 containers failed ] [ 3 tests found ] [ 0 tests skipped ] [ 3 tests started ] [ 0 tests aborted ] [ 3 tests successful ] [ 0 tests failed ] BUILD SUCCESSFUL
この機能の別の適用例としては、インタフェース契約に対するテストが考えられます。
例えば、Object.equals
や Comparable.compareTo
の実装クラスが
どう振る舞うべきかのテストを次のように書くことができます。
public interface Testable<T> {
T createValue();
}
public interface EqualsContract<T> extends Testable<T> {
T createNotEqualValue();
@Test
default void valueEqualsItself() {
T value = createValue();
assertEquals(value, value);
}
@Test
default void valueDoesNotEqualNull() {
T value = createValue();
assertFalse(value.equals(null));
}
@Test
default void valueDoesNotEqualDifferentValue() {
T value = createValue();
T differentValue = createNotEqualValue();
assertNotEquals(value, differentValue);
assertNotEquals(differentValue, value);
}
}
public interface ComparableContract<T extends Comparable<T>> extends Testable<T> {
T createSmallerValue();
@Test
default void returnsZeroWhenComparedToItself() {
T value = createValue();
assertEquals(0, value.compareTo(value));
}
@Test
default void returnsPositiveNumberWhenComparedToSmallerValue() {
T value = createValue();
T smallerValue = createSmallerValue();
assertTrue(value.compareTo(smallerValue) > 0);
}
@Test
default void returnsNegativeNumberWhenComparedToLargerValue() {
T value = createValue();
T smallerValue = createSmallerValue();
assertTrue(smallerValue.compareTo(value) < 0);
}
}
テストクラスでこれらの契約インターフェースを実装することで、対応するテストケースを 継承することができます。もちろん、抽象メソッドは自分で実装する必要があります。
class StringTests implements ComparableContract<String>, EqualsContract<String> {
@Override
public String createValue() {
return "foo";
}
@Override
public String createSmallerValue() {
return "bar"; // 'b' < 'f' in "foo"
}
@Override
public String createNotEqualValue() {
return "baz";
}
}
前述のテストはサンプル目的であり、完全なものではありません。 |
3.13. 繰り返しテスト
JUnit Jupiterは、@RepeatedTest
アノテーションを使って指定した回数だけ
繰り返しテストを実行する機能を提供しています。
繰り返しテストの1回毎の呼び出しは、ライフサイクルコールバックや拡張機能など、通常の
@Test
メソッドの実行と同じように振る舞います。
次の例は、自動的に10回繰り返す repeatedTest()
を宣言する方法を示しています。
@RepeatedTest(10)
void repeatedTest() {
// ...
}
繰り返し回数を指定するだけでなく、@RepeatedTest
アノテーションの name
属性を使って、繰り返し実行毎の表示名を変更することもできます。表示名は、
静的なテキストと動的なプレースホルダーを組み合わせたパターンにできます。
以下が、現在サポートされているプレースホルダーです。
-
{displayName}
:@RepeatedTest
メソッドの表示名 -
{currentRepetition}
: 現在の実行回数 -
{totalRepetitions}
: トータルの実行回数
デフォルトの表示名は、"repetition {currentRepetition} of {totalRepetitions}"
というパターンに従います。そのため、前述の repeatedTest()
に対する表示名は、
repetition 1 of 10
, repetition 2 of 10
のようになります。
もし @RepeatedTest
メソッドの名前を含めたい場合は、カスタムのパターンを指定するか、
定義済みの RepeatedTest.LONG_DISPLAY_NAME
パターンを指定できます。
後者は、"{displayName} :: repetition {currentRepetition} of {totalRepetitions}"
というパターンと同等で、repeatedTest() :: repetition 1 of 10
,
repeatedTest() :: repetition 2 of 10
のようになります。
現在の繰り返し回数やトータルの繰り返し回数をプログラムから取得するためには、
RepetitionInfo
インスタンスを @RepeatedTest
, @BeforeEach
, @AfterEach
メソッドのいずれかに注入させることができます。
3.13.1. 繰り返しテストの例
この節の最後の RepeatedTestsDemo
クラスは、繰り返しテストの様々な例を示しています。
repeatedTest()
メソッドは、前の節で紹介した例と同じです。一方、
repeatedTestWithRepetitionInfo()
は、トータルの繰り返し回数を取得するために
RepetitionInfo
インスタンスをテストに注入させる方法を示しています。
その次の2つのメソッドは、@RepeatedTest
メソッドに対するカスタムの @DisplayName
を各繰り返しの表示名に含める方法を示しています。customDisplayName()
は、
カスタムの表示名とパターンを組み合わせて指定し、生成された表示名を検証するのに
TestInfo
を使っています。
{displayName}
が @DisplayName
の宣言から Repeat!
となり、
{currentRepetition}/{totalRepetitions}
が 1/1
となります。
一方、customDisplayNameWithLongPattern()
は前述の定義済みパターン
RepeatedTest.LONG_DISPLAY_NAME
を使っています。
repeatedTestInGerman()
は、繰り返しテストの表示名を外国語(この場合、ドイツ語)
に翻訳する方法を示しています。各繰り返しの表示名は、Wiederholung 1 von 5
,
Wiederholung 2 von 5
のようになります。
beforeEach()
メソッドは @BeforeEach
アノテーションが付与されているため、
繰り返しテストの個々の繰り返し実行の度に実行されます。TestInfo
と
RepetitionInfo
をメソッドに注入させることで、現在実行中の繰り返しテストに
関する情報を取得できることが分かります。INFO
レベルのログを有効にして
RepeatedTestsDemo
を実行すると、次のような出力となります。
INFO: About to execute repetition 1 of 10 for repeatedTest INFO: About to execute repetition 2 of 10 for repeatedTest INFO: About to execute repetition 3 of 10 for repeatedTest INFO: About to execute repetition 4 of 10 for repeatedTest INFO: About to execute repetition 5 of 10 for repeatedTest INFO: About to execute repetition 6 of 10 for repeatedTest INFO: About to execute repetition 7 of 10 for repeatedTest INFO: About to execute repetition 8 of 10 for repeatedTest INFO: About to execute repetition 9 of 10 for repeatedTest INFO: About to execute repetition 10 of 10 for repeatedTest INFO: About to execute repetition 1 of 5 for repeatedTestWithRepetitionInfo INFO: About to execute repetition 2 of 5 for repeatedTestWithRepetitionInfo INFO: About to execute repetition 3 of 5 for repeatedTestWithRepetitionInfo INFO: About to execute repetition 4 of 5 for repeatedTestWithRepetitionInfo INFO: About to execute repetition 5 of 5 for repeatedTestWithRepetitionInfo INFO: About to execute repetition 1 of 1 for customDisplayName INFO: About to execute repetition 1 of 1 for customDisplayNameWithLongPattern INFO: About to execute repetition 1 of 5 for repeatedTestInGerman INFO: About to execute repetition 2 of 5 for repeatedTestInGerman INFO: About to execute repetition 3 of 5 for repeatedTestInGerman INFO: About to execute repetition 4 of 5 for repeatedTestInGerman INFO: About to execute repetition 5 of 5 for repeatedTestInGerman
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.logging.Logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import org.junit.jupiter.api.TestInfo;
class RepeatedTestsDemo {
private Logger logger = // ...
@BeforeEach
void beforeEach(TestInfo testInfo, RepetitionInfo repetitionInfo) {
int currentRepetition = repetitionInfo.getCurrentRepetition();
int totalRepetitions = repetitionInfo.getTotalRepetitions();
String methodName = testInfo.getTestMethod().get().getName();
logger.info(String.format("About to execute repetition %d of %d for %s", //
currentRepetition, totalRepetitions, methodName));
}
@RepeatedTest(10)
void repeatedTest() {
// ...
}
@RepeatedTest(5)
void repeatedTestWithRepetitionInfo(RepetitionInfo repetitionInfo) {
assertEquals(5, repetitionInfo.getTotalRepetitions());
}
@RepeatedTest(value = 1, name = "{displayName} {currentRepetition}/{totalRepetitions}")
@DisplayName("Repeat!")
void customDisplayName(TestInfo testInfo) {
assertEquals(testInfo.getDisplayName(), "Repeat! 1/1");
}
@RepeatedTest(value = 1, name = RepeatedTest.LONG_DISPLAY_NAME)
@DisplayName("Details...")
void customDisplayNameWithLongPattern(TestInfo testInfo) {
assertEquals(testInfo.getDisplayName(), "Details... :: repetition 1 of 1");
}
@RepeatedTest(value = 5, name = "Wiederholung {currentRepetition} von {totalRepetitions}")
void repeatedTestInGerman() {
// ...
}
}
Unicodeテーマを有効にした ConsoleLauncher
で RepeatedTestsDemo
を実行すると、
コンソールには以下のように出力されます。
├─ RepeatedTestsDemo ✔ │ ├─ repeatedTest() ✔ │ │ ├─ repetition 1 of 10 ✔ │ │ ├─ repetition 2 of 10 ✔ │ │ ├─ repetition 3 of 10 ✔ │ │ ├─ repetition 4 of 10 ✔ │ │ ├─ repetition 5 of 10 ✔ │ │ ├─ repetition 6 of 10 ✔ │ │ ├─ repetition 7 of 10 ✔ │ │ ├─ repetition 8 of 10 ✔ │ │ ├─ repetition 9 of 10 ✔ │ │ └─ repetition 10 of 10 ✔ │ ├─ repeatedTestWithRepetitionInfo(RepetitionInfo) ✔ │ │ ├─ repetition 1 of 5 ✔ │ │ ├─ repetition 2 of 5 ✔ │ │ ├─ repetition 3 of 5 ✔ │ │ ├─ repetition 4 of 5 ✔ │ │ └─ repetition 5 of 5 ✔ │ ├─ Repeat! ✔ │ │ └─ Repeat! 1/1 ✔ │ ├─ Details... ✔ │ │ └─ Details... :: repetition 1 of 1 ✔ │ └─ repeatedTestInGerman() ✔ │ ├─ Wiederholung 1 von 5 ✔ │ ├─ Wiederholung 2 von 5 ✔ │ ├─ Wiederholung 3 von 5 ✔ │ ├─ Wiederholung 4 von 5 ✔ │ └─ Wiederholung 5 von 5 ✔
3.14. パラメーター化テスト
訳注:計算機科学の用語に従うのであれば、 argument を 実引数(メソッドを呼び出す側から見た引数)、 parameter を 仮引数(メソッドを呼ばれる側から見た引数) と区別して訳すべきだが、パラメーター化テストの説明では前者の argument を パラメーター と訳してしまった方が 直感的にイメージしやすいと訳者は考える。 原文でも両者の区別があいまいな箇所があるため、以降では 訳者の解釈に従って意訳している。気になる場合は、原文をあたること。 |
パラメーター化テストは、異なる実引数でテストを複数回実行できるようにします。
通常の @Test
メソッドに似ていますが、@ParameterizedTest
アノテーションを
使って宣言します。各呼び出しに対するパラメーターを生成するための ソース (source)
を少なくとも1つは宣言し、そのパラメーターはテストメソッドで 消費 (consume)
する必要があります。
以下は、パラメーターのソースとして String
配列を指定するために @ValueSource
アノテーションを使用した例を示しています。
@ParameterizedTest
@ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
void palindromes(String candidate) {
assertTrue(isPalindrome(candidate));
}
上のパラメーター化テストメソッドを実行すると、各実行が別々にレポートされます。
例えば、ConsoleLauncher
を使うと次のように出力されます。
palindromes(String) ✔ ├─ [1] racecar ✔ ├─ [2] radar ✔ └─ [3] able was I ere I saw elba ✔
パラーメーター化テストは、現在 実験中 の機能です。 詳細は、実験的なAPI の表を確認してください。 |
3.14.1. 必要なセットアップ
パラメーター化テストを使うには、junit-jupiter-params
への依存を追加する必要があります。
詳細は、依存関係メタデータ を参照してください。
3.14.2. パラメーターの消費
パラメーター化テストのメソッドは、通常は設定されたソース
(パラメーターのソース 参照)
からパラメーターのインデックスとメソッドの仮引数のインデックスが1対1となるように
パラメーターを 消費 します
(@CsvSource の例を参照)。
しかし、ソースのすべてのパラメーターを単一のオブジェクトに 集約
してメソッドに渡すこともできます
(パラメーターの集約 参照)。
また、ParameterResolver
を使って追加の引数を渡すこともできます
(例えば、TestInfo
や TestReporter
のインスタンスなど)。
パラメーター化テストメソッドは、次のルールに従って仮引数を宣言しなければなりません。
-
最初に、インデックス付き引数 (indexed argument) を0個以上宣言します
-
その次に、アグリゲーター (aggregator) を0個以上宣言します
-
最後に、
ParameterResolver
によって渡される引数を0個以上宣言します
ここで、インデックス付き引数 (indexed argument) は、ArgumentsProvider
が生成した Arguments
中の指定されたインデックスに対するパラメーターです。
このパラメーターは、パラメーター化テストメソッドの仮引数リストで
同じインデックスに実引数として渡されます。
アグリゲーター (aggregator) は、ArgumentsAccessor
型または @AggregateWith
アノテーションが付与された仮引数です。
3.14.3. パラメーターのソース
JUnit Jupiterは、あらかじめいくつかの ソース アノテーションを提供しています。
以降では、これらのアノテーションについて簡単な説明とサンプルを示します。
より詳細な情報は、org.junit.jupiter.params.provider
パッケージのJavaDocを参照してください。
@ValueSource
@ValueSource
は、最もシンプルなソースの1つです。リテラル値の配列を指定できますが、
パラメーター化テストの1回の実行につき1つのパラメーターしか与えることができません。
@ValueSource
では、以下の型のリテラル値がサポートされています。
-
short
-
byte
-
int
-
long
-
float
-
double
-
char
-
java.lang.String
-
java.lang.Class
例えば、次の @ParameterizedTest
メソッドは、値 1
, 2
, 3
をパラメーターとして
3回呼び出されます。
@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void testWithValueSource(int argument) {
assertTrue(argument > 0 && argument < 4);
}
@EnumSource
@EnumSource
は、Enum
定数を指定する便利な方法を提供します。このアノテーションでは、
省略可能な names
属性を指定すると、その列挙定数だけが使われます。
省略すると、次の例のようにすべての列挙定数が使われます。
@ParameterizedTest
@EnumSource(TimeUnit.class)
void testWithEnumSource(TimeUnit timeUnit) {
assertNotNull(timeUnit);
}
@ParameterizedTest
@EnumSource(value = TimeUnit.class, names = { "DAYS", "HOURS" })
void testWithEnumSourceInclude(TimeUnit timeUnit) {
assertTrue(EnumSet.of(TimeUnit.DAYS, TimeUnit.HOURS).contains(timeUnit));
}
@EnumSource
アノテーションは、テストメソッドに渡される列挙定数をさらに細かく制御するために、
省略可能な mode
属性も提供しています。例えば、一部の名前をもつ列挙定数だけ除外したり、
正規表現で列挙定数を指定したりすることができます。
@ParameterizedTest
@EnumSource(value = TimeUnit.class, mode = EXCLUDE, names = { "DAYS", "HOURS" })
void testWithEnumSourceExclude(TimeUnit timeUnit) {
assertFalse(EnumSet.of(TimeUnit.DAYS, TimeUnit.HOURS).contains(timeUnit));
assertTrue(timeUnit.name().length() > 5);
}
@ParameterizedTest
@EnumSource(value = TimeUnit.class, mode = MATCH_ALL, names = "^(M|N).+SECONDS$")
void testWithEnumSourceRegex(TimeUnit timeUnit) {
String name = timeUnit.name();
assertTrue(name.startsWith("M") || name.startsWith("N"));
assertTrue(name.endsWith("SECONDS"));
}
@MethodSource
@MethodSource
は、テストクラスまたは外部のクラスの ファクトリ
メソッドによるパラメーターの指定を可能にします。
テストクラス内のファクトリメソッドは、@TestInstance(Lifecycle.PER_CLASS)
アノテーションが付与されていない限り、static
でなければいけません。
一方、外部クラスのファクトリメソッドは、常に static
でなければいけません。
これらのファクトリメソッドは、引数を受け取ることもできません。
ファクトリメソッドは、 @ParameterizedTest
メソッドの各呼び出しに対して
実際の引数として渡される パラメーター の ストリーム を生成しなければなりません。
一般的に言えば、これは Arguments
の Stream
(つまり、Stream<Arguments>
)
となりますが、実際の戻り値は様々な型をとりえます。ここでいう "ストリーム" とは、
JUnitが確実に Stream
へ変換できるものであれば何でも構いません。例えば、
Stream
, DoubleStream
, LongStream
, IntStream
, Collection
,
Iterator
, Iterable
, オブジェクト配列, プリミティブ型の配列などです。
ストリームの "パラメーター" は、 Arguments
のインスタンス、オブジェクト配列
(つまり、Object[]
)、あるいはパラメーター化テストメソッドが1つだけしか
パラメーターを受け取らない場合には単一の値となります。
パラメーターが1つしか必要なければ、次の例のようにパラメーターのインスタンスを
Stream
で返すことができます。
@ParameterizedTest
@MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument) {
assertNotNull(argument);
}
static Stream<String> stringProvider() {
return Stream.of("foo", "bar");
}
もし @MethodSource
でファクトリメソッドの名前を明示的に指定しなかった場合、JUnit Jupiter
は @ParameterizedTest
メソッドと同じ名前をもつファクトリメソッドを自動的に探します。
@ParameterizedTest
@MethodSource
void testWithSimpleMethodSourceHavingNoValue(String argument) {
assertNotNull(argument);
}
static Stream<String> testWithSimpleMethodSourceHavingNoValue() {
return Stream.of("foo", "bar");
}
プリミティブ型のストリーム (DoubleStream
, IntStream
, LongStream
)
もサポートされています。
@ParameterizedTest
@MethodSource("range")
void testWithRangeMethodSource(int argument) {
assertNotEquals(9, argument);
}
static IntStream range() {
return IntStream.range(0, 20).skip(10);
}
パラメーター化テストメソッドが複数の仮引数を宣言している場合、以下で示すように Arguments
インスタンスかオブジェクト配列を要素とするコレクション、ストリーム、配列のいずれかを返す必要があります
(サポートされる戻り値型のさらなる詳細は、@MethodSource
のJavadocを参照)。
arguments(Object…)
は Arguments
インターフェースで定義されるstaticファクトリメソッドである
点に注意してください。また、Arguments.of(Object…)
を arguments(Object…)
の代わりに使用することもできます。
@ParameterizedTest
@MethodSource("stringIntAndListProvider")
void testWithMultiArgMethodSource(String str, int num, List<String> list) {
assertEquals(3, str.length());
assertTrue(num >=1 && num <=2);
assertEquals(2, list.size());
}
static Stream<Arguments> stringIntAndListProvider() {
return Stream.of(
arguments("foo", 1, Arrays.asList("a", "b")),
arguments("bar", 2, Arrays.asList("x", "y"))
);
}
次の例で示すように、メソッドの完全修飾名 を指定することで、外部の static
な
ファクトリ メソッドを参照することもできます。
package example;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
class ExternalMethodSourceDemo {
@ParameterizedTest
@MethodSource("example.StringsProviders#tinyStrings")
void testWithExternalMethodSource(String tinyString) {
// test with tiny string
}
}
class StringsProviders {
static Stream<String> tinyStrings() {
return Stream.of(".", "oo", "OOO");
}
}
@CsvSource
@CsvSource
は、パラメーターのリストをカンマ区切りの値(String
リテラル)
で指定できるようにします。
@ParameterizedTest
@CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" })
void testWithCsvSource(String first, int second) {
assertNotNull(first);
assertNotEquals(0, second);
}
@CsvSource
は、シングルクォート '
を引用符として使います。
上の例の 'baz, qux'
と、以下のテーブルを参照してください。
引用符で囲まれた空の値 ''
は空の String
になりますが、
(引用符で囲まれない)完全に 空 の値は null
と解釈されます。
null
の代入先の型がプリミティブ型の場合は、
ArgumentConversionException
が発生します。
Example Input | Resulting Argument List |
---|---|
|
|
|
|
|
|
|
|
@CsvFileSource
@CsvFileSource
は、クラスパスにあるCSVファイルを使えるようにします。
CSVファイルの各行は、パラメーター化テストの1回の実行になります。
@ParameterizedTest
@CsvFileSource(resources = "/two-column.csv", numLinesToSkip = 1)
void testWithCsvFileSource(String first, int second) {
assertNotNull(first);
assertNotEquals(0, second);
}
Country, reference
Sweden, 1
Poland, 2
"United States of America", 3
@CsvSource のシンタックスとは異なり、@CsvFileSource はダブルクォート "
を引用符として使います。上の例の、"United States of America" を参考にしてください。
引用符で囲まれた空の値 "" は空の String になりますが、
(引用符で囲まれない)完全に 空 の値は null と解釈されます。
null の代入先の型がプリミティブ型の場合は、
ArgumentConversionException が発生します。
|
@ArgumentsSource
@ArgumentsSource
は、カスタムの再利用可能な ArgumentsProvider
を指定する場合に使えます。
@ParameterizedTest
@ArgumentsSource(MyArgumentsProvider.class)
void testWithArgumentsSource(String argument) {
assertNotNull(argument);
}
public class MyArgumentsProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of("foo", "bar").map(Arguments::of);
}
}
3.14.4. パラメーターの変換
拡大変換
JUnit Jupiterは、@ParameterizedTest
に与えられたパラメーターに対して、
プリミティブ型の
拡大変換 をサポートしています。例えば、@ValueSource(ints = { 1, 2, 3 })
アノテーションが付与されたパラメーター化テストでは、テストメソッドの仮引数を
int
型だけでなく long
や float
、double
型でも宣言することができます。
暗黙的な変換
@CsvSource
のようなユースケースをサポートするために、JUnit Jupiter
は多くの組み込みの型変換を提供しています。
変換処理は、メソッドの仮引数の型に依存します。
例えば、@ParameterizedTest
が TimeUnit
型の仮引数を宣言し、
ソースから実際に渡される型が String
の場合、その文字列は対応する
TimeUnit
列挙定数に自動的に変換されます。
@ParameterizedTest
@ValueSource(strings = "SECONDS")
void testWithImplicitArgumentConversion(TimeUnit argument) {
assertNotNull(argument.name());
}
String
インスタンスは、今のところ次のようなターゲット型に暗黙的に変換されます。
Target Type | Example |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String → Object変換のフォールバック
上の表で示した文字列からターゲット型への暗黙的な変換に加えて、JUnit Jupiter
は String
型からターゲット型に自動変換するフォールバックの仕組みも提供しています。
この変換は、ターゲット型が以下に示す ファクトリメソッド か ファクトリコンストラクタ
を1つだけ宣言している場合に機能します。
-
ファクトリメソッド: ターゲット型に宣言された非privateの
static
メソッドで、String
型の引数を1つだけ受け取ってターゲット型のインスタンスを返す。 メソッドの名前は任意であり、特定のルールに従う必要はない。 -
ファクトリコンストラクタ: ターゲット型に宣言された非privateのコンストラクタで、
String
型の引数を1つだけ受け取ってインスタンスを作る。
複数の ファクトリメソッド が見つかった場合、それらは無視されます。 ファクトリメソッド と ファクトリコンストラクタ が両方見つかった場合は、 ファクトリメソッドの方が使われます。 |
例えば、次の @ParameterizedTest
メソッドでは、Book
型の引数は
Book.fromTitle(String)
ファクトリメソッドに本のタイトルとして "42 Cats"
を渡して実行することで作られます。
@ParameterizedTest
@ValueSource(strings = "42 Cats")
void testWithImplicitFallbackArgumentConversion(Book book) {
assertEquals("42 Cats", book.getTitle());
}
public class Book {
private final String title;
private Book(String title) {
this.title = title;
}
public static Book fromTitle(String title) {
return new Book(title);
}
public String getTitle() {
return this.title;
}
}
明示的な変換
暗黙的な変換を使う代わりに、@ConvertWith
アノテーションで
仮引数の変換に使う ArgumentConverter
を明示的に指定することもできます。
@ParameterizedTest
@EnumSource(TimeUnit.class)
void testWithExplicitArgumentConversion(
@ConvertWith(ToStringArgumentConverter.class) String argument) {
assertNotNull(TimeUnit.valueOf(argument));
}
public class ToStringArgumentConverter extends SimpleArgumentConverter {
@Override
protected Object convert(Object source, Class<?> targetType) {
assertEquals(String.class, targetType, "Can only convert to String");
return String.valueOf(source);
}
}
明示的な型変換器はテストまたは拡張機能の作者に実装されることを想定しています。
そのため、junit-jupiter-params
モジュールは参照実装として JavaTimeArgumentConverter
の1つだけしか提供していません。これは、合成アノテーション JavaTimeConversionPattern
経由で使用できます。
@ParameterizedTest
@ValueSource(strings = { "01.01.2017", "31.12.2017" })
void testWithExplicitJavaTimeConverter(
@JavaTimeConversionPattern("dd.MM.yyyy") LocalDate argument) {
assertEquals(2017, argument.getYear());
}
3.14.5. パラメーターの集約
デフォルトでは、@ParameterizedTest
のメソッドに与えられる各パラメーター
は、1つの仮引数に対応します。結果として、ソースが多数のパラメーターを生成する場合、
メソッドシグネチャが大きく(仮引数が多く)なります。
そのような場合には、複数の仮引数を定義する代わりに ArgumentsAccessor
を使うことができます。このAPIを使うと、テストメソッドに渡した単一の
ArgumentsAccessor
経由ですべてのパラメーターにアクセスすることができます。
加えて、
暗黙的な変換
で説明した型変換もサポートされます。
@ParameterizedTest
@CsvSource({
"Jane, Doe, F, 1990-05-20",
"John, Doe, M, 1990-10-22"
})
void testWithArgumentsAccessor(ArgumentsAccessor arguments) {
Person person = new Person(arguments.getString(0),
arguments.getString(1),
arguments.get(2, Gender.class),
arguments.get(3, LocalDate.class));
if (person.getFirstName().equals("Jane")) {
assertEquals(Gender.F, person.getGender());
}
else {
assertEquals(Gender.M, person.getGender());
}
assertEquals("Doe", person.getLastName());
assertEquals(1990, person.getDateOfBirth().getYear());
}
ArgumentsAccessor
型の仮引数には、自動的に ArgumentsAccessor
のインスタンスが注入されます。
カスタムアグリゲーター
ArgumentsAccessor
を使って @ParameterizedTest
メソッドのパラメーターに
直接アクセスする以外に、JUnit Jupiterはカスタムの再利用可能な
アグリゲーター (aggregator) もサポートしています。
カスタムアグリゲーターを使うには、ArgumentsAggregator
インターフェースを実装し、
@ParameterizedTest
メソッドの仮引数に @AggregateWith
アノテーションを使って登録します。集約した結果は、
パラメーター化テストが実行されるときに
対象の仮引数に対する実引数として渡されます。
@ParameterizedTest
@CsvSource({
"Jane, Doe, F, 1990-05-20",
"John, Doe, M, 1990-10-22"
})
void testWithArgumentsAggregator(@AggregateWith(PersonAggregator.class) Person person) {
// perform assertions against person
}
public class PersonAggregator implements ArgumentsAggregator {
@Override
public Person aggregateArguments(ArgumentsAccessor arguments, ParameterContext context) {
return new Person(arguments.getString(0),
arguments.getString(1),
arguments.get(2, Gender.class),
arguments.get(3, LocalDate.class));
}
}
複数のパラメーター化テストメソッドに対して何回も @AggregateWith(MyTypeAggregator.class)
を宣言していることに気付いたら、@AggregateWith(MyTypeAggregator.class)
をメタアノテーションとして付与した @CsvToMyType
のようなカスタム 合成アノテーション
を作りたくなるでしょう。
次の例は、実際にカスタムの @CsvToPerson
アノテーションを作る例を示しています。
@ParameterizedTest
@CsvSource({
"Jane, Doe, F, 1990-05-20",
"John, Doe, M, 1990-10-22"
})
void testWithCustomAggregatorAnnotation(@CsvToPerson Person person) {
// perform assertions against person
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@AggregateWith(PersonAggregator.class)
public @interface CsvToPerson {
}
3.14.6. 表示名のカスタマイズ
デフォルトでは、パラメーター化テストの表示名には、呼び出しインデックスとすべてのパラメーターの
String
表現が含まれます。ただし、@ParameterizedTest
アノテーションの name
属性を指定すれば、次の例のようにカスタマイズすることもできます。
@DisplayName("Display name of container")
@ParameterizedTest(name = "{index} ==> first=''{0}'', second={1}")
@CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" })
void testWithCustomDisplayNames(String first, int second) {
}
上のメソッドを ConsoleLauncher
で実行すると、以下のような出力となります。
Display name of container ✔ ├─ 1 ==> first='foo', second=1 ✔ ├─ 2 ==> first='bar', second=2 ✔ └─ 3 ==> first='baz, qux', second=3 ✔
次のプレースホルダーがサポートされています。
Placeholder | Description |
---|---|
|
現在の呼び出しインデックス(1始まり) |
|
カンマ区切りの完全なパラメーターのリスト |
|
個々のパラメーター |
3.14.7. ライフサイクルと相互運用性
パラメーター化テストの各呼び出しは、通常の @Test
メソッドと同じライフサイクルをもちます。
例えば、@BeforeEach
メソッドが各呼び出しの前に実行されます。
動的テスト と同様に、パラメーター化テストの各呼び出しは、
IDEのテストツリーの中に1つずつ表示されます。同じテストクラスの中で、
@Test
メソッドと @ParameterizedTest
メソッドを混在させるのも自由です。
ParameterResolver
拡張を @ParameterizedTest
メソッドと使いたいかもしれません。
その場合は、パラメーターのソースから渡される引数を先に宣言する必要があります。
テストクラスは、パラメーター化テストだけでなく通常のテストを含んでいる可能性もあるので、
パラメーターをライフサイクルメソッド (例えば、@BeforeEach
)
やテストコンストラクタに渡すことができません。
@BeforeEach
void beforeEach(TestInfo testInfo) {
// ...
}
@ParameterizedTest
@ValueSource(strings = "foo")
void testWithRegularParameterResolver(String argument, TestReporter testReporter) {
testReporter.publishEntry("argument", argument);
}
@AfterEach
void afterEach(TestInfo testInfo) {
// ...
}
3.15. テストテンプレート
@TestTemplate
メソッドは、通常のテストケースではなく、テストケースのテンプレートです。
登録したプロバイダが返す実行コンテキストの数に応じて、複数回呼び出されるよう設計されています。
そのため、テストテンプレートは TestTemplateInvocationContextProvider
と一緒に使う必要があります。
テストテンプレートメソッドの各呼び出しは、ライフサイクルコールバックや拡張機能など、
通常の @Test
メソッドの実行と同じように振る舞います。使用例については、
テストテンプレートに実行コンテキストを与える を参照してください。
3.16. 動的テスト
アノテーション で説明したJUnit Jupiterの標準の @Test
アノテーションは、JUnit 4の @Test
アノテーションととてもよく似ています。
どちらもテストケースを実装するメソッドを示します。これらのテストケースは、
完全にコンパイル時に指定され、その振る舞いが実行時には変えられないという意味で、
静的なものです。 前提条件 (Assumption) の機能は、動的な振る舞いの基本を
提供しますが、表現力は意図的に限定されています。
JUnit Jupiterでは、これらの標準的なテストに加えて、完全に新しいプログラミング
モデルが導入されました。それは、動的テスト です。動的テストは、
@TestFactory
アノテーションを付与したファクトリメソッドによって、
実行時に生成されます。
@Test
メソッドとは異なり、@TestFactory
メソッド自身はテストケースではなく、
テストケースのファクトリとなります。ファクトリの出力が動的テストになります。
技術的に言うと、@TestFactory
メソッドは、DynamicNode
インスタンスの
Stream
, Collection
, Iterable
, Iterator
, 配列のいずれかを
返さなければなりません。DynamicNode
のインスタンス化可能なサブクラスには、
DynamicContainer
と DynamicTest
があります。DynamicContainer
インスタンスは、表示名 と子どもの DynamicNode
リストで構成され、
入れ子になった DynamicNode
の階層を作成できるようになっています。
DynamicTest
インスタンスが遅延実行されることで、動的かつ非決定的な
テストケースの生成を実現します。
@TestFactory
が返した Stream
は、stream.close()
呼び出しによって
適切にクローズされます。これにより、Files.lines()
などのリソースを
安全に使うことができます。
@Test
メソッドと同じように、@TestFactory
メソッドも private
または
static
であってはいけません。また、ParameterResolvers
で解決される
パラメーターを宣言することもできます。
DynamicTest
は、実行時に生成されるテストケースで、表示名 と Executable
で構成されます。Executable
は、@FunctionalInterface
であり、
動的テストの実装が ラムダ式 または メソッド参照 で与えられることを意味します。
動的テストのライフサイクル
動的テストの実行ライフサイクルは、通常の @Test とはかなり違います。
特に、個々の動的テストに対しては、ライフサイクルコールバックはありません。
これは、@BeforeEach や @AfterEach メソッドとその拡張コールバックが、
@TestFactory メソッドに対して実行され、個々の 動的テスト
に対しては実行されないことを意味しています。言い換えれば、動的テストのラムダ式から
テストインスタンスのフィールドにアクセスしていたとしても、同じ @TestFactory
メソッドから生成された個々の動的テストを実行する間は、コールバックメソッドにも
拡張機能にもそのフィールドはリセットされないのです。
|
JUnit Jupiter 5.3.0 の時点では、動的テストは常にファクトリメソッドで 生成しなければなりません。ただし、将来のリリースで、登録の仕組みが追加されるかもしれません。
動的テストは現在 実験中 の機能です。詳細は、 実験的なAPI の表を参照してください。 |
3.16.1. 動的テストの例
次の DynamicTestsDemo
クラスは、テストファクトリと動的テストの例を示しています。
最初のメソッドは、不正な戻り値型を返しています。不正な戻り値型はコンパイル時には
検出できないため、実行時に検出されて JUnitException
がスローされます。
その次の5つのメソッドは、DynamicTest
インスタンスの Collection
, Iterable
,
Iterator
, Stream
を生成するとてもシンプルな例です。ほとんどの例は、
動的な振る舞いではなく、単にサポートされている戻り値の型をデモしています。
しかし、dynamicTestsFromStream()
と dynamicTestsFromIntStream()
は、
与えられた文字列リストや数値の範囲に対して簡単に動的なテストを生成できることを
示しています。
その次のメソッドは、真に動的な性質のものです。generateRandomNumberOfTests()
は、乱数を生成する Iterator
、表示名の生成器、テストの実行器の3つを実装し、
これらを DynamicTest.stream()
に渡しています。
generateRandomNumberOfTests()
の非決定的な振る舞いは、
もちろんテストの再現性に反するため注意して使うべきですが、
動的テストの高い表現力とパワーを示すのに役立っています。
最後のメソッドは、DynamicContainer
を使って動的テストを入れ子階層にする例を示しています。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.DynamicContainer.dynamicContainer;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.function.Function;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.function.ThrowingConsumer;
class DynamicTestsDemo {
// This will result in a JUnitException!
@TestFactory
List<String> dynamicTestsWithInvalidReturnType() {
return Arrays.asList("Hello");
}
@TestFactory
Collection<DynamicTest> dynamicTestsFromCollection() {
return Arrays.asList(
dynamicTest("1st dynamic test", () -> assertTrue(true)),
dynamicTest("2nd dynamic test", () -> assertEquals(4, 2 * 2))
);
}
@TestFactory
Iterable<DynamicTest> dynamicTestsFromIterable() {
return Arrays.asList(
dynamicTest("3rd dynamic test", () -> assertTrue(true)),
dynamicTest("4th dynamic test", () -> assertEquals(4, 2 * 2))
);
}
@TestFactory
Iterator<DynamicTest> dynamicTestsFromIterator() {
return Arrays.asList(
dynamicTest("5th dynamic test", () -> assertTrue(true)),
dynamicTest("6th dynamic test", () -> assertEquals(4, 2 * 2))
).iterator();
}
@TestFactory
DynamicTest[] dynamicTestsFromArray() {
return new DynamicTest[] {
dynamicTest("7th dynamic test", () -> assertTrue(true)),
dynamicTest("8th dynamic test", () -> assertEquals(4, 2 * 2))
};
}
@TestFactory
Stream<DynamicTest> dynamicTestsFromStream() {
return Stream.of("A", "B", "C")
.map(str -> dynamicTest("test" + str, () -> { /* ... */ }));
}
@TestFactory
Stream<DynamicTest> dynamicTestsFromIntStream() {
// Generates tests for the first 10 even integers.
return IntStream.iterate(0, n -> n + 2).limit(10)
.mapToObj(n -> dynamicTest("test" + n, () -> assertTrue(n % 2 == 0)));
}
@TestFactory
Stream<DynamicTest> generateRandomNumberOfTests() {
// Generates random positive integers between 0 and 100 until
// a number evenly divisible by 7 is encountered.
Iterator<Integer> inputGenerator = new Iterator<>() {
Random random = new Random();
int current;
@Override
public boolean hasNext() {
current = random.nextInt(100);
return current % 7 != 0;
}
@Override
public Integer next() {
return current;
}
};
// Generates display names like: input:5, input:37, input:85, etc.
Function<Integer, String> displayNameGenerator = (input) -> "input:" + input;
// Executes tests based on the current input value.
ThrowingConsumer<Integer> testExecutor = (input) -> assertTrue(input % 7 != 0);
// Returns a stream of dynamic tests.
return DynamicTest.stream(inputGenerator, displayNameGenerator, testExecutor);
}
@TestFactory
Stream<DynamicNode> dynamicTestsWithContainers() {
return Stream.of("A", "B", "C")
.map(input -> dynamicContainer("Container " + input, Stream.of(
dynamicTest("not null", () -> assertNotNull(input)),
dynamicContainer("properties", Stream.of(
dynamicTest("length > 0", () -> assertTrue(input.length() > 0)),
dynamicTest("not empty", () -> assertFalse(input.isEmpty()))
))
)));
}
}
3.17. 並列実行
デフォルトでは、JUnit Jupiterのテストはシングルスレッドで逐次実行されます。バージョン
5.3からは、オプトインの機能として(例えば高速化のために)テストの並列実行を利用できます。
並列実行を有効にするには、単に junit-platform.properties
ファイルで
設定パラメーター junit.jupiter.execution.parallel.enabled
に true
を指定するだけです(その他の選択肢については、設定パラメーター を参照)。
有効にすると、JUnit Jupiterエンジンは与えられた 設定 と宣言的に指定された 同期化 に従って、 テストツリーのすべてのレベルのテストを並列実行します。なお、 標準出力/標準エラー出力のキャプチャ 機能は別途有効にする必要がある点に注意してください。
テストの並列実行は、今のところ 実験的な 機能です。JUnitチームがこの機能を改善し、 最終的には 昇格 できるよう、試しに使ってみてフィードバックをください。 |
3.17.1. 設定
希望する並列数やプールの最大サイズなどのプロパティは、
ParallelExecutionConfigurationStrategy
を使って設定できます。
JUnit Platformは、すぐに使える2つの実装(dynamic
と fixed
)を提供しています。
なお、代わりに独自の custom
戦略を実装することもできます。
並列戦略を選択するには、設定パラメーター junit.jupiter.execution.parallel.config.strategy
に次のいずれかを指定します。
dynamic
-
利用可能なプロセッサ/コア数に、設定パラメーター
junit.jupiter.execution.parallel.config.dynamic.factor
の値 (デフォルトは1
)を掛けた数に基づいて並列数を計算します。 fixed
-
設定パラメーター
junit.jupiter.execution.parallel.config.fixed.parallelism
の値を並列数として使用します。 custom
-
設定パラメーター
junit.jupiter.execution.parallel.config.custom.class
で指定された独自のParallelExecutionConfigurationStrategy
実装を使って、 並列数を決定します。
もし並列戦略が指定されていなかった場合、JUnit Jupiterは dynamic
戦略を使います。
つまり、並列数は利用可能なプロセッサ/コア数の数と同じになります。
3.17.2. 同期化
JUnit Jupiterは、異なるテスト間で共有リソースを使うときの実行モデルを変更し、
同期化を可能にするためのアノテーションベースの仕組みを2つ
org.junit.jupiter.api.parallel
パッケージで提供しています。
並列実行が有効な場合、デフォルトではすべてのクラスとメソッドが同時に実行されます。
@Execution
アノテーションを使うことで、アノテーションが付与された要素と
(もしあれば)サブ要素の実行モデルを変更することができます。
次の2つのモードが利用可能です。
SAME_THREAD
-
親と同じスレッドで実行することを強制します。例えば、テストメソッドに指定した場合、 該当メソッドはテストクラスの
@BeforeAll
メソッドや@AfterAll
メソッドを 実行するスレッドと同じスレッドで実行されます。 CONCURRENT
-
リソース制約で同一スレッドでの実行が強制されない限り、別スレッドで並列実行されます。
加えて、@ResourceLock
アノテーションを使うと、テストクラスやテストメソッドが
同期化されたアクセスを必要とする共有リソースを使用していると宣言できます。
仮に次のサンプルのテストが並列実行されたとすると、結果は不安定 (flaky) 、
つまり成功したり失敗したりします。
というのも、同じシステムプロパティを読み書きする競合状態があるからです
(訳注: @ResourceLock
による同期化がない仮定の話)。
@Execution(CONCURRENT)
class SharedResourcesDemo {
private Properties backup;
@BeforeEach
void backup() {
backup = new Properties();
backup.putAll(System.getProperties());
}
@AfterEach
void restore() {
System.setProperties(backup);
}
@Test
@ResourceLock(value = SYSTEM_PROPERTIES, mode = READ)
void customPropertyIsNotSetByDefault() {
assertNull(System.getProperty("my.prop"));
}
@Test
@ResourceLock(value = SYSTEM_PROPERTIES, mode = READ_WRITE)
void canSetCustomPropertyToFoo() {
System.setProperty("my.prop", "foo");
assertEquals("foo", System.getProperty("my.prop"));
}
@Test
@ResourceLock(value = SYSTEM_PROPERTIES, mode = READ_WRITE)
void canSetCustomPropertyToBar() {
System.setProperty("my.prop", "bar");
assertEquals("bar", System.getProperty("my.prop"));
}
}
共有リソースへのアクセスが @ResourceLock
アノテーションで宣言されている場合、
JUnit Jupiterエンジンはこの情報を活用し、互いにコンフリクトするテストが同時に
実行されないよう保証します。
使用されるリソースを一意に特定する文字列に加えて、アクセスモードを指定することもできます。
同じリソースの READ
アクセスを要求する2つのテストは同時に実行することができますが、
READ_WRITE
アクセスを要求するテストが実行中の場合は実行できません。
4. テストを実行する
4.1. IDEのサポート
4.1.1. IntelliJ IDEA
IntelliJ IDEAは、バージョン2016.2からJUnit Platform上でのテスト実行をサポートしています。
詳細は、
IntelliJ IDEAブログの投稿
を参照してください。ただし、実際にはIntelliJ IDEA 2017.3またはそれより新しいバージョンの
利用が推奨される点に注意してください。というのも、プロジェクトで利用されるAPIバージョンに応じて
junit-platform-launcher
, junit-jupiter-engine
, junit-vintage-engine
のJARを自動的にダウンロードしてくれるからです。
IntelliJ IDEAのバージョン2017.3より前のリリースは、JUnit 5 の特定のバージョンを同梱している点に注意してください。もしもJUnit Jupiter の新しいバージョンを使いたい場合、IDE内でのテスト実行はバージョンのコンフリクトで 失敗する可能性があります。そのような場合は、IntelliJ IDEAに同梱されている JUnit 5より新しいバージョンを使うために、以下の手順に従ってください。 |
JUnit 5の異なるバージョン (例えば、 5.3.0) を使うには、
junit-platform-launcher
, junit-jupiter-engine
, junit-vintage-engine
の対応するバージョンのJARをクラスパスに追加する必要があります。
// Only needed to run tests in a version of IntelliJ IDEA that bundles older versions
testRuntime("org.junit.platform:junit-platform-launcher:1.3.0")
testRuntime("org.junit.jupiter:junit-jupiter-engine:5.3.0")
testRuntime("org.junit.vintage:junit-vintage-engine:5.3.0")
<!-- Only needed to run tests in a version of IntelliJ IDEA that bundles older versions -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>
4.1.2. Eclipse
Eclipse IDEは、Oxygen.1a (4.7.1a)リリースからJUnit Platformをサポートしています。
EclipseでJUnit 5を使うための情報は、公式ドキュメント Eclipse Project Oxygen.1a (4.7.1a) - New and Noteworthy の Eclipse support for JUnit 5 の節を参照してください。
4.1.3. その他のIDE
本書執筆時点では、IntelliJ IDEAとEclipse以外のIDEは、JUnit Platform 上でのテスト実行を直接はサポートしていません。しかし、JUnitチームは あなたが使っているIDEでJUnit 5を試せるように、2つの中間解を提供しています。 Console Launcher を手動で使うか、 JUnit 4ベースのランナー でテストを実行することができます。
4.2. ビルドサポート
4.2.1. Gradle
Gradleは バージョン4.6 から、
JUnit Platformでテストを実行するための機能を
ネイティブでサポート
しています。有効にするには、build.gradle
の test
タスク宣言内で useJUnitPlatform()
を指定するだけです。
test {
useJUnitPlatform()
}
タグやテストエンジンによるフィルタリングもサポートしています。
test {
useJUnitPlatform {
includeTags 'fast', 'smoke & feature-a'
// excludeTags 'slow', 'ci'
includeEngines 'junit-jupiter'
// excludeEngines 'junit-vintage'
}
}
使用できるオプションの一覧は、 Gradle公式ドキュメント を参照してください。
JUnit Platform Gradleプラグインは廃止
JUnitチームによって開発されていた |
設定パラメーター
Gradle標準の test
タスクは、テストの発見・実行に影響を与えるJUnit Platformの
設定パラメーター を指定する専用DSL
を今のところ提供していません。
しかし、以下に示すようにビルドスクリプト内でシステムプロパティを使うか、
junit-platform.properties
ファイルを使うことで、設定パラメーターを指定できます。
test {
// ...
systemProperty 'junit.jupiter.conditions.deactivate', '*'
systemProperties = [
'junit.jupiter.extensions.autodetection.enabled': 'true',
'junit.jupiter.testinstance.lifecycle.default': 'per_class'
]
// ...
}
テストエンジンを設定する
テストを実行させるためには、TestEngine
の実装がクラスパスに存在しなければなりません。
JUnit Jupiterベースのテストをサポートするためには、JUnit Jupiter API
に対する testCompile
依存と、JUnit Jupiter TestEngine
実装に対する testRuntime
依存を次のように指定する必要があります。
dependencies {
testCompile("org.junit.jupiter:junit-jupiter-api:5.3.0")
testRuntime("org.junit.jupiter:junit-jupiter-engine:5.3.0")
}
JUnit Platformは、JUnit 4ベースのテストも実行することができます。
そのためには、JUnit 4に対する testCompile
依存と、JUnit Vintage
TestEngine
実装に対する testRuntime
依存が必要です。
dependencies {
testCompile("junit:junit:4.12")
testRuntime("org.junit.vintage:junit-vintage-engine:5.3.0")
}
ロギングを設定する(省略可)
JUnitは、java.util.logging
パッケージ(別名、JUL)の Java Logging API
を警告やデバッグ情報の出力に利用しています。設定オプションについては、
LogManager
の公式ドキュメントを参照してください。
ログを Log4j や Logback のような他のロギングフレームワークにリダイレクトする
ことも可能です。LogManager
のカスタム実装を提供するロギングフレームワークを
使う場合は、java.util.logging.manager
システムプロパティに LogManager
実装クラスの 完全修飾名 を指定してください。以下は、Log4j 2.x
(詳細は、 Log4j JDK Logging Adapter 参照)を設定する例です。
test {
systemProperty 'java.util.logging.manager', 'org.apache.logging.log4j.jul.LogManager'
}
その他のロギングフレームワークは、java.util.logging
のログをリダイレクトする
方法が異なります。例えば Logback では、
JULからSLF4Jへのブリッジ
を実行時のクラスパスに依存関係として追加して使います。
4.2.2. Maven
JUnitチームによって開発されていた junit-platform-surefire-provider
は非推奨となり、JUnit Platform 1.4で削除が予定されています。
代わりに、Maven Surefireを使用してください。
|
バージョン 2.22.0 から、
Maven SurefireはJUnit Platform上でテストを実行するための
ネイティブサポート
を提供しています。 junit5-jupiter-starter-maven
プロジェクトの pom.xml
ファイルがその使い方を示すとともに、Mavenビルドを設定するための出発点となるでしょう。
テストエンジンを設定する
Maven Surefireにテストを実行させるためには、TestEngine
の実装が少なくとも1つ
実行時のクラスパスに必要です。
JUnit Jupiterベースのテストをサポートするためには、JUnit Jupiter APIと
JUnit Jupiter TestEngine
実装に対する test
スコープの依存を
次のように指定する必要があります。
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
</plugins>
</build>
...
<dependencies>
...
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>
...
</dependencies>
...
Maven Surefireは、JUnit 4ベースのテストも実行することができます。
そのためには、次のようにJUnit 4とJUnit Vintage TestEngine
実装に対する test
スコープの依存が必要です。
...
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
</plugins>
</build>
...
<dependencies>
...
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.3.0</version>
<scope>test</scope>
</dependency>
...
</dependencies>
...
テストクラス名でフィルタリングする
Maven Surefireプラグインは、完全修飾名が次のパターンにマッチするテストクラスを探します。
-
**/Test*.java
-
**/*Test.java
-
**/*Tests.java
-
**/*TestCase.java
なお、すべてのネストクラス(staticな内部クラスも含む)はデフォルトで除外されます。
ただし、pom.xml
ファイルの include
および exclude
ルールを明示的に設定することで、デフォルトの動作を変更することもできます。
例えば、Maven Surefireがstaticな内部クラスを除外しないようにするなどです。
...
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<excludes>
<exclude/>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
...
詳細は、 Maven Surefireのドキュメント Inclusions and Exclusions of Tests を参照してください。
タグでフィルタリングする
次のように、タグまたは タグ式 を使ってテストをフィルタリングすることもできます。
-
タグ または タグ式 をテスト対象に含めるには、
groups
を指定します。 -
タグ または タグ式 をテスト対象から除外するには、
excludedGroups
を指定します。
...
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<groups>acceptance | !feature-a</groups>
<excludedGroups>integration, regression</excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
...
設定パラメーター
configurationParameters
プロパティにJavaの Properties
ファイル形式の
キー・値のペアを与えるか、junit-platform.properties
ファイルを与えることで、
テストの発見・実行に影響を与えるJUnit Platformの
設定パラメーター を指定できます。
...
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<properties>
<configurationParameters>
junit.jupiter.conditions.deactivate = *
junit.jupiter.extensions.autodetection.enabled = true
junit.jupiter.testinstance.lifecycle.default = per_class
</configurationParameters>
</properties>
</configuration>
</plugin>
</plugins>
</build>
...
4.2.3. Ant
Ant のバージョン 1.10.3
から、
JUnit Platform上でのテスト実行をネイティブサポートするために
junitlauncher
タスクが導入されました。junitlauncher
タスクは、単にJUnit Platform
を起動して、選択したテストを渡すだけの責務をもちます。その後、JUnit Platform
が登録されたテストエンジンにテストの発見・実行を移譲します。
junitlauncher
タスクは、
ユーザーがテストエンジンに実行させたいテストを選択するための
リソース集合
のように、Antの既存機能と可能な限り一貫性を保とうとしています。
これにより、Antの他のコアタスクと比べても、一貫性があり直感的なものになっています。
Ant 1.10.3 でリリースされた junitlauncher タスクは、
JUnit Platformを起動する基本的かつ最低限のサポートだけを提供します。
追加の機能強化 (異なるJVMにforkしてのテスト実行サポートを含む) は、
今後のAntリリースで利用可能になる予定です。
|
junit5-jupiter-starter-ant
プロジェクトの build.xml
ファイルが使い方を示しています。
基本的な使い方
次の例は、単一のテストクラス (org.myapp.test.MyFirstJUnit5Test
)
を選択するように junitlauncher
タスクを設定する方法を示します。
<path id="test.classpath">
<!-- The location where you have your compiled classes -->
<pathelement location="${build.classes.dir}" />
</path>
<!-- ... -->
<junitlauncher>
<classpath refid="test.classpath" />
<test name="org.myapp.test.MyFirstJUnit5Test" />
</junitlauncher>
test
要素で実行したい単一のテストクラスを指定することができます。
classpath
要素でJUnit Platformを起動するのに使うクラスパスを指定することができます。
このクラスパスは、実行するテストクラスを探すのにも使われます。
次の例は、複数の場所からテストクラスを選択するように junitlauncher
タスクを設定する方法を示します。
<path id="test.classpath">
<!-- The location where you have your compiled classes -->
<pathelement location="${build.classes.dir}" />
</path>
....
<junitlauncher>
<classpath refid="test.classpath" />
<testclasses outputdir="${output.dir}">
<fileset dir="${build.classes.dir}">
<include name="org/example/**/demo/**/" />
</fileset>
<fileset dir="${some.other.dir}">
<include name="org/myapp/**/" />
</fileset>
</testclasses>
</junitlauncher>
上の例のように testclasses
要素を使うと、異なる場所にある複数のテストクラスを選択できます。
使い方と設定オプションに関する詳細は、Ant公式ドキュメントの
junitlauncher
タスク
を参照してください。
4.3. Console Launcher
ConsoleLauncher
は、コンソールからJUnit Platformを起動するための
Javaのコマンドラインアプリケーションです。例えば、JUnit VintageとJUnit Jupiter
のテストを実行し、結果をコンソールに表示するのに使えます。
すべての依存関係を含んだ実行可能な junit-platform-console-standalone-1.3.0.jar
がMavenセントラルリポジトリの
junit-platform-console-standalone
ディレクトリで公開されています。スタンドアロン版の ConsoleLauncher
は、次のように
実行する ことができます。
java -jar junit-platform-console-standalone-1.3.0.jar <オプション>
出力の例は次の通りです。
├─ JUnit Vintage │ └─ example.JUnit4Tests │ └─ standardJUnit4Test ✔ └─ JUnit Jupiter ├─ StandardTests │ ├─ succeedingTest() ✔ │ └─ skippedTest() ↷ for demonstration purposes └─ A special test case ├─ Custom test name containing spaces ✔ ├─ ╯°□°)╯ ✔ └─ 😱 ✔ Test run finished after 64 ms [ 5 containers found ] [ 0 containers skipped ] [ 5 containers started ] [ 0 containers aborted ] [ 5 containers successful ] [ 0 containers failed ] [ 6 tests found ] [ 1 tests skipped ] [ 5 tests started ] [ 0 tests aborted ] [ 5 tests successful ] [ 0 tests failed ]
終了コード
ConsoleLauncher は、コンテナやテストが失敗するとステータスコード 1 で終了します。
テストが見つからず、かつコマンドラインオプション --fail-if-no-tests が指定されていた場合は、
ConsoleLauncher はステータスコード 2 で終了します。その他の場合は、終了コードは 0 です。
|
4.3.1. オプション
Usage: ConsoleLauncher [-h] [--disable-ansi-colors] [--fail-if-no-tests] [--scan-modules] [--scan-classpath[=PATH[;|:PATH...]]]... [--details=MODE] [--details-theme=THEME] [--reports-dir=DIR] [--config=KEY=VALUE]... [--exclude-package=PKG]... [--include-package=PKG]... [-c=CLASS]... [-cp=PATH[;|:PATH...]]... [-d=DIR]... [-e=ID]... [-E=ID]... [-f=FILE]... [-m=NAME]... [-n=PATTERN]... [-N=PATTERN]... [-o=NAME]... [-p=PKG]... [-r=RESOURCE]... [-t=TAG]... [-T=TAG]... [-u=URI]... Launches the JUnit Platform from the console. -h, --help Display help information. --disable-ansi-colors Disable ANSI colors in output (not supported by all terminals). --details=MODE Select an output details mode for when tests are executed. Use one of: none, summary, flat, tree, verbose. If 'none' is selected, then only the summary and test failures are shown. Default: tree. --details-theme=THEME Select an output details tree theme for when tests are executed. Use one of: ascii, unicode. Default: unicode. -cp, --classpath, --class-path=PATH[;|:PATH...] Provide additional classpath entries -- for example, for adding engines and their dependencies. This option can be repeated. --fail-if-no-tests Fail and return exit status code 2 if no tests are found. --reports-dir=DIR Enable report output into a specified local directory (will be created if it does not exist). --scan-modules EXPERIMENTAL: Scan all resolved modules for test discovery. -o, --select-module=NAME EXPERIMENTAL: Select single module for test discovery. This option can be repeated. --scan-classpath, --scan-class-path[=PATH[;|:PATH...]] Scan all directories on the classpath or explicit classpath roots. Without arguments, only directories on the system classpath as well as additional classpath entries supplied via -cp (directories and JAR files) are scanned. Explicit classpath roots that are not on the classpath will be silently ignored. This option can be repeated. -u, --select-uri=URI Select a URI for test discovery. This option can be repeated. -f, --select-file=FILE Select a file for test discovery. This option can be repeated. -d, --select-directory=DIR Select a directory for test discovery. This option can be repeated. -p, --select-package=PKG Select a package for test discovery. This option can be repeated. -c, --select-class=CLASS Select a class for test discovery. This option can be repeated. -m, --select-method=NAME Select a method for test discovery. This option can be repeated. -r, --select-resource=RESOURCE Select a classpath resource for test discovery. This option can be repeated. -n, --include-classname=PATTERN Provide a regular expression to include only classes whose fully qualified names match. To avoid loading classes unnecessarily, the default pattern only includes class names that begin with "Test" or end with "Test" or "Tests". When this option is repeated, all patterns will be combined using OR semantics. Default: [^(Test.*|.+[.$]Test.*|.*Tests?)$] -N, --exclude-classname=PATTERN Provide a regular expression to exclude those classes whose fully qualified names match. When this option is repeated, all patterns will be combined using OR semantics. --include-package=PKG Provide a package to be included in the test run. This option can be repeated. --exclude-package=PKG Provide a package to be excluded from the test run. This option can be repeated. -t, --include-tag=TAG Provide a tag or tag expression to include only tests whose tags match. When this option is repeated, all patterns will be combined using OR semantics. -T, --exclude-tag=TAG Provide a tag or tag expression to exclude those tests whose tags match. When this option is repeated, all patterns will be combined using OR semantics. -e, --include-engine=ID Provide the ID of an engine to be included in the test run. This option can be repeated. -E, --exclude-engine=ID Provide the ID of an engine to be excluded from the test run. This option can be repeated. --config=KEY=VALUE Set a configuration parameter for test discovery and execution. This option can be repeated.
4.3.2. 引数ファイル (@ファイル)
プラットフォームによっては、多数のオプションや長い引数をもつコマンドラインを作ろうとすると、 システムのコマンドライン文字数の上限に引っかかるかもしれません。
バージョン1.3から、ConsoleLauncher
は 引数ファイル (@ファイル としても知られる)
をサポートします。引数ファイルは、コマンドに与える引数を記述したファイルです。
内部で使用している picocli コマンドラインパーサーは、
@
文字から始まる引数を見つけると、そのファイルの中身を引数リストとして展開します。
ファイル内の引数は、スペースまたは改行で分割できます。引数自身が空白を含む場合は、
引数全体をダブルクォートかシングルクォートで囲まなければなりません。
例えば、"-f=My Files/Stuff.java"
のようになります。
引数ファイルが存在しないか読み込めない場合は、無視されずにそのリテラル文字列が引数として扱われます。
その結果、 "unmatched argument" エラーメッセージが表示される結果になりがちです。
picocli.trace
システムプロパティを DEBUG
に設定してからコマンドを実行すれば、
このようなエラーをトラブルシュートすることができます。
複数の @ファイル をコマンドラインに指定することもできます。指定するパスは、 カレントディレクトリからの相対パスにするか、絶対パスにします。
実際の引数が @
文字から始まる場合は、@
をもう1つ追加してエスケープします。
例えば、@@somearg
は @somearg
と解釈され、展開はされません。
4.4. JUnit Platformの実行にJUnit 4を使う
JUnitPlatform
ランナーは、JUnit Platformのプログラミングモデルに従ったテスト
(例えば、JUnit Jupiterのテストクラス)をJUnit 4環境で実行可能にするための
JUnit 4ベースの Runner
です。
テストクラスに @RunWith(JUnitPlatform.class)
アノテーションを付与すると、
まだJUnit Platformを直接はサポートしていないけれどもJUnit 4ならサポートしている
IDEやビルドシステムでも実行できるようになります。
JUnit PlatformはJUnit 4にない機能をもっているため、特にレポート周り
(表示名 vs. 技術名 を参照)など、
JUnit Platformの機能のサブセットしかサポートすることができません。
しかし、さしあたっては JUnitPlatform ランナーを使って始めるのが簡単です。
|
4.4.1. セットアップ
クラスパスに以下のライブラリとその依存ライブラリが必要です。Group IDやArtifact ID、 バージョンの詳細については、 依存関係メタデータ を参照してください。
4.4.2. 表示名 vs. 技術名
訳注:本文書では Display Name に対して 表示名 という訳語を使用し、 本節で登場する Technical Name に対しては 技術名 という訳語を使用した。 しかし、後者は直感的ではないと思うので、適切な訳があればフィードバックをいただきたい。 |
@RunWith(JUnitPlatform.class)
ランナーで実行されるクラスにカスタムの
表示名 (display name) を定義するためには、@SuiteDisplayName
アノテーションを付与します。
デフォルトでは、 表示名 はテストの成果物に使われます。しかし、Gradleや
Mavenのようなビルドツールが JUnitPlatform
ランナーを使う場合、
生成されるテストレポートには、テストクラスの単純名や
特殊文字を含むカスタム表示名ではなく、完全修飾クラス名のような
技術名 (technical name) が必要になることがあります。
レポート出力で 技術名 を有効にするためには、
@RunWith(JUnitPlatform.class)
と一緒に @UseTechnicalNames
アノテーションを宣言してください。
@UseTechnicalNames
を付与すると、@SuiteDisplayName
でしたカスタム表示名は無視される点に注意してください。
4.4.3. 単一のテストクラス
JUnitPlatform
ランナーを使う方法の1つは、テストクラスに直接
@RunWith(JUnitPlatform.class)
アノテーションを付与することです。
以下の例のテストメソッドには、org.junit.Test
(JUnit Vintage) ではなく、
org.junit.jupiter.api.Test
(JUnit Jupiter)
アノテーションが付与されている点に注意してください。さらに、
この場合はテストクラスを public
にしなければならない点にも注意してください。
そうしないと、一部のIDEやビルドツールではJUnit 4のテストクラスとして
認識されません。
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
@RunWith(JUnitPlatform.class)
public class JUnit4ClassDemo {
@Test
void succeedingTest() {
/* no-op */
}
@Test
void failingTest() {
fail("Failing for failing's sake.");
}
}
4.4.4. テストスイート
複数のテストクラスがある場合、次の例のようにテストスイートを作成できます。
import org.junit.platform.runner.JUnitPlatform;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.SuiteDisplayName;
import org.junit.runner.RunWith;
@RunWith(JUnitPlatform.class)
@SuiteDisplayName("JUnit 4 Suite Demo")
@SelectPackages("example")
public class JUnit4SuiteDemo {
}
JUnit4SuiteDemo
は、example
パッケージとそのサブパッケージから
すべてのテストを探して実行します。デフォルトでは、名前が Test
で始まるか、
Test
または Tests
で終わるテストクラスだけを実行します。
追加の設定オプション
@SelectPackages 以外にも、テストを検索したりフィルタリングしたりするための
設定オプションがあります。詳細は、
Javadoc
を参照してください。
|
4.5. 設定パラメーター
どのテストクラスやテストエンジンを含むか、どのパッケージを検索するか、といったことを
プラットフォームに指示するだけでなく、特定のテストエンジンや拡張機能に固有の
追加の設定パラメーターを渡したい場合もあります。例えば、JUnit Jupiterの TestEngine
は、次のユースケースのために 設定パラメーター をサポートしています。
設定パラメーター は、テキストベースのキーと値のペアで、JUnit Platform で動作するテストエンジンに次のいずれかの方法で渡されます。
-
LauncherDiscoveryRequestBuilder
クラスのconfigurationParameter()
またはconfigurationParameters()
メソッドを使って構築したリクエストをLauncher
API に渡します。JUnit Platform が提供するツールを使ってテストを実行する場合、設定パラメーターは次のように指定できます。-
Console Launcher:
--config
コマンドラインオプションを使います -
Gradle:
systemProperty
またはsystemProperties
DSLを使います -
Maven Surefireプロバイダ:
configurationParameters
プロパティを使います
-
-
JVMシステムプロパティ
-
JUnit Platform設定ファイル: クラスパスのルートに
junit-platform.properties
という名前で配置され、JavaのProperties
ファイルと同じシンタックスに従います。
設定パラメーターは、上で定義された順番に従って解決されます。つまり、
Launcher に直接与えられた設定パラメーターの方が、システムプロパティや設定ファイルで
与えられたものより優先されます。同様に、システムプロパティで与えられた設定パラメーターの方が、
設定ファイルで与えられたものより優先されます。
|
4.6. タグ式
タグ式は、 !
, &
, |
演算子からなるブール式です。
演算子の優先順位を調整するために、(
と )
も使えます。
演算子 | 意味 | 結合性 |
---|---|---|
|
not |
right |
|
and |
left |
|
or |
left |
テストに直交するタグを付与している場合、実行するテストを選択するのにタグ式は便利です。 テストの種類 (例えば、micro, integration, end-to-end) と機能 (例えば、 foo, bar, baz) のタグを付与すると、次のようなタグ式が使えます。
タグ式 | 該当するテスト |
---|---|
foo |
foo に対するすべてのテスト |
bar | baz |
bar または baz に対するすべてのテスト |
bar & baz |
bar かつ baz に対するすべてのテスト |
foo & !end-to-end |
foo に対するテストのうち、end-to-end レベル以外のすべてのテスト |
(micro | integration) & (foo | baz) |
foo または baz に対するテストのうち、micro または integration レベルのすべてのテスト |
4.7. 標準出力/標準エラー出力のキャプチャ
バージョン1.3から、JUnit Platformは System.out
と System.err
への出力をキャプチャする機能をオプトインでサポートします。有効にするには、
junit.platform.output.capture.stdout
および junit.platform.output.capture.stderr
設定パラメーター に true
を指定するだけです。
加えて、junit.platform.output.capture.maxBuffer
を使用することで、
テストやコンテナ毎に使用されるバッファサイズの最大値を設定することができます。
有効にすると、JUnit Platformは該当の出力をキャプチャし、stdout
または stderr
キーを使ってレポート情報に格納した上で、テストやコンテナの終了をレポートする直前に
TestExecutionListener
インスタンスへ通知します。
キャプチャされた出力は、コンテナやテストを実行するのに使用したスレッドからの出力だけを 含む点に注意してください。その他のスレッドからの出力は除外されます。というのも、 特に テストを並列実行している 場合には、 出力をテストやコンテナ単位でひも付けるのは不可能だからです。
出力のキャプチャは、今のところ 実験的な 機能です。JUnitチームがこの機能を改善し、 最終的には 昇格 できるよう、試しに使ってみてフィードバックをください。 |
5. 拡張モデル
5.1. 概要
JUnit 4の Runner
, @Rule
, @ClassRule
などの拡張ポイントとは異なり、
JUnit Jupiterの拡張モデルは、単一の一貫したコンセプトである Extension
API
で構成されます。ただし、Extension
自身はただのマーカーインターフェースである点に
注意してください。
5.2. 拡張機能の登録
拡張機能は、 @ExtendWith
を使って 宣言的に 登録するか、
@RegisterExtension
を使って 手続き的に 登録するか、あるいは
Javaの ServiceLoader
の仕組みを使って 自動的に 登録することができます。
5.2.1. 宣言的な登録
開発者は、テストインターフェースやテストクラス、テストメソッド、
合成アノテーション に
@ExtendWith(…)
アノテーションを付与し、
拡張機能として登録したいクラスの参照を指定することで
1つ以上の拡張機能を 宣言的に 登録することができます。
例えば、特定のテストメソッドに RandomParametersExtension
を登録したい場合は、
テストメソッドに次のようにアノテーションを付与します。
@ExtendWith(RandomParametersExtension.class)
@Test
void test(@Random int i) {
// ...
}
特定のクラスとそのサブクラスのすべてのテストに RandomParametersExtension
を登録したい場合は、テストクラスに次のようにアノテーションを付与します。
@ExtendWith(RandomParametersExtension.class)
class MyTests {
// ...
}
複数の拡張機能は、次のように同時に登録することができます。
@ExtendWith({ FooExtension.class, BarExtension.class })
class MyFirstTests {
// ...
}
別の方法としては、次のように個別に登録することができます。
@ExtendWith(FooExtension.class)
@ExtendWith(BarExtension.class)
class MySecondTests {
// ...
}
拡張機能の登録順序
@ExtendWith で宣言的に登録された拡張機能は、ソースコード上での宣言順で実行されます。
例えば、MyFirstTests と MySecondTests のテスト実行は、FooExtension と
BarExtension によって まさにこの順序で 拡張されます。
|
5.2.2. 手続き的な登録
開発者は、テストクラスのフィールドに
@RegisterExtension
アノテーションを付与することで、
拡張機能を 手続き的に 登録することができます。
拡張機能を @ExtendWith
で
宣言的に 登録する場合、拡張機能の設定はアノテーション経由でしか行なえません。
しかし、拡張機能を @RegisterExtension
で登録する場合は、
拡張機能のコンストラクタやstaticファクトリメソッド、
ビルダーAPIに引数を渡して 手続き的に 設定することができます。
@RegisterExtension フィールドは、private または null (評価時)
であってはなりませんが、static か非 static かはどちらでもかまいません。
|
staticフィールド
@RegisterExtension
フィールドが static
の場合、その拡張機能は
@ExtendWith
でクラスレベルに登録される拡張機能の後で登録されます。
そのような staticな拡張機能 は、実装する拡張APIに制限がありません。
そのため、staticフィールドとして登録される拡張機能は、
BeforeAllCallback
, AfterAllCallback
, TestInstancePostProcessor
のようなクラスレベルやインスタンスレベルの拡張APIだけでなく、
BeforeEachCallback
などのようなメソッドレベルの拡張APIも実装できます。
次の例では、テストクラスの server
フィールドは WebServerExtension
がサポートするビルダーパターンを使って手続き的に初期化されます。設定された
WebServerExtension
は、クラスレベルの拡張機能として自動的に登録され、
例えば、すべてのテストを開始する前にサーバーを起動したり、
すべてのテストが完了した後でサーバーを停止したりすることができます。
加えて、@BeforeEach
, @AfterEach
, @Test
メソッドだけでなく、
@BeforeAll
や @AfterAll
のようなstaticなライフサイクルメソッドも
必要であれば server
フィールド経由でこの拡張機能のインスタンスにアクセスできます。
class WebServerDemo {
@RegisterExtension
static WebServerExtension server = WebServerExtension.builder()
.enableSecurity(false)
.build();
@Test
void getProductList() {
WebClient webClient = new WebClient();
String serverUrl = server.getServerUrl();
// Use WebClient to connect to web server using serverUrl and verify response
assertEquals(200, webClient.get(serverUrl + "/products").getResponseStatus());
}
}
Kotlinでのstaticフィールド
プログラミング言語Kotlinには、static
フィールドがありません。しかし、
アノテーションを使うと、コンパイラにstaticフィールドを生成させることができます。
先に述べた通り、@RegisterExtension
フィールドは private
または null
になってはならないため、private
フィールドを生成する @JvmStatic
アノテーションをKotlinで 使うことはできません。
代わりに、@JvmField
アノテーションを使ってください。
次の例は、前節の WebServerDemo
をKotlinに移植したものです。
class KotlinWebServerDemo {
companion object {
@JvmField
@RegisterExtension
val server = WebServerExtension.builder()
.enableSecurity(false)
.build()
}
@Test
fun getProductList() {
// Use WebClient to connect to web server using serverUrl and verify response
val webClient = WebClient()
val serverUrl = server.serverUrl
assertEquals(200, webClient.get("$serverUrl/products").responseStatus)
}
}
インスタンスフィールド
@RegisterExtension
フィールドが非static (つまり、インスタンスフィールド)
の場合、その拡張機能はテストクラスがインスタンス化され、登録済みの各
TestInstancePostProcessor
がテストインスタンスの事後処理
(拡張機能のインスタンスをアノテーションの付与されたフィールドに注入するなど)
をした後で登録されます。そのため、インスタンスフィールドの拡張機能 が
BeforeAllCallback
, AfterAllCallback
, TestInstancePostProcessor
のようなクラスレベルやインスタンスレベルの拡張APIを実装しても意味がありません。
デフォルトでは、インスタンスフィールドの拡張機能は @ExtendWith
でメソッドレベルに登録される拡張機能より 後で 登録されます。しかし、
テストクラスが @TestInstance(Lifecycle.PER_CLASS)
モードに設定されている場合は、
@ExtendWith
でメソッドレベルに登録される拡張機能の 前に 登録されます。
次の例では、テストクラスの docs
フィールドは lookUpDocsDir()
メソッドを呼び出した結果を DocumentationExtension
のstaticファクトリメソッド
forPath()
に渡すことで、手続き的に初期化されます。設定された
DocumentationExtension
は、メソッドレベルの拡張機能として自動的に登録されます。
加えて、@BeforeEach
, @AfterEach
, @Test
メソッドは
必要であれば docs
フィールド経由でこの拡張機能のインスタンスにアクセスできます。
class DocumentationDemo {
static Path lookUpDocsDir() {
// return path to docs dir
}
@RegisterExtension
DocumentationExtension docs = DocumentationExtension.forPath(lookUpDocsDir());
@Test
void generateDocumentation() {
// use this.docs ...
}
}
5.2.3. 自動的な登録
アノテーションを使った拡張機能の
宣言的な登録 と
手続き的な登録 に加えて、
JUnit JupiterはJavaの java.util.ServiceLoader
の仕組みを使った拡張機能の
グローバルな登録 もサポートしています。
これにより、クラスパスから利用可能なサードパーティの拡張機能を自動検出し、
自動的に登録させることができます。
具体的には、JARファイルの /META-INF/services
フォルダの中に
org.junit.jupiter.api.extension.Extension
という名前のファイルを作成し、
クラスの完全修飾名を指定することで拡張機能を登録できます。
拡張機能の自動検出を有効にする
自動検出は高度な機能なので、デフォルトでは有効になっていません。有効化するには、
設定パラメーター junit.jupiter.extensions.autodetection.enabled
に true
を指定します。これは、JVMのシステムプロパティか、
Launcher
に渡される LauncherDiscoveryRequest
の 設定パラメーター、
あるいはJUnit Platform 設定ファイルで指定することができます
(詳細は、設定パラメーター を参照)。
例えば、拡張機能の自動検出を有効化するには、JVMを次のシステムプロパティ付きで起動します。
-Djunit.jupiter.extensions.autodetection.enabled=true
自動検出が有効化されると、ServiceLoader
の仕組みで検知された拡張機能は、
JUnit Jupiterのグローバルな拡張機能 (例えば、TestInfo
や TestReporter
のサポート) の後で拡張機能レジストリに登録されます。
5.3. 条件付きテスト実行
ExecutionCondition
は、プログラムの 条件付きテスト実行 のための Extension
APIを定めています。
ExecutionCondition
は、コンテナ (例えば、テストクラス) がもつテストを与えられた
ExtensionContext
で実行すべきか判断するためにコンテナ毎に評価されます。
同様に、ExecutionCondition
は、個々のテストメソッドを与えられた ExtensionContext
で実行すべきか判断するためにテスト毎に評価されます。
複数の ExecutionCondition
拡張が登録された場合、無効 と判定する拡張機能が1つでもあれば、
コンテナやテストはただちに無効化されます。別の拡張機能がすでにコンテナやテストを無効化していることがあるので、
ある拡張機能が必ず評価されるという保証はありません。言い換えると、論理OR演算子の短絡評価のように評価されます。
具体的な例は、DisabledCondition
と @Disabled
のソースコードを参照してください。
5.3.1. 条件を非アクティブにする
訳注:テストの条件 ( |
ときには、特定の条件をアクティブにせずにテストスイートを実行できると有用な場合があります。
例えば、@Disabled
アノテーションが付与されているテストであっても、今もまだ 壊れた
ままかを確認するために実行したいと思うことがあるかもしれません。そのためには、
設定パラメーター junit.jupiter.conditions.deactivate
を使って、
現在のテスト実行に対してどの条件を非アクティブ (つまり、評価されない) にするか
パターンを指定するだけです。パターンは、JVMのシステムプロパティか、 Launcher
に渡される
LauncherDiscoveryRequest
の 設定パラメーター、あるいはJUnit Platform
設定ファイルで指定することができます (詳細は、設定パラメーター を参照)。
例えば、JUnitの @Disabled
条件を非アクティブにするには、
JVMを次のシステムプロパティ付きで起動します。
-Djunit.jupiter.conditions.deactivate=org.junit.*DisabledCondition
パターンマッチング構文
junit.jupiter.conditions.deactivate
のパターンがアスタリスク (*
)
のみからなる場合、すべての条件が非アクティブになります。一方、
登録された条件の完全修飾クラス名 (FQCN) に対するパターンマッチも使えます。
パターン中のドット (.
) は、FQCN中のドット (.
) またはドル記号 ($
) にマッチします。
アスタリスク (*
) は、FQCN中の1つ以上の文字にマッチします。
ほかのすべての文字は、FQCN中の文字に1対1でマッチします。
例:
-
*
: すべての条件を非アクティブにします。 -
org.junit.*
:org.junit
パッケージおよびすべてのサブパッケージにある条件を非アクティブにします。 -
*.MyCondition
: 単純クラス名がMyCondition
である条件をすべて非アクティブにします。 -
*System*
: 単純クラス名にSystem
を含む条件をすべて非アクティブにします。 -
org.example.MyCondition
: FQCNがorg.example.MyCondition
である条件を非アクティブにします。
5.4. テストインスタンスのファクトリ
TestInstanceFactory
は、テストクラスのインスタンスを 生成する
ための Extension APIを定めています。
一般的なユースケースとしては、DI(依存性注入)フレームワークからテストインスタンスを取得したり、 テストクラスのインスタンス生成にstaticファクトリメソッドを呼んだりすることです。
TestInstanceFactory
が登録されていない場合は、
フレームワークは単にテストクラスの 唯一の コンストラクタを実行して初期化します。
このとき、コンストラクタの引数は、登録済みの ParameterResolver
拡張で解決されます。
TestInstanceFactory
を実装する拡張機能は、テストインターフェースや
トップレベルのテストクラス、あるいは @Nested
テストクラスに対しても登録できます。
|
5.5. テストインスタンスの後処理
TestInstancePostProcessor
は、テストインスタンスの 後処理 をするための Extension
APIを定めています。
よくあるユースケースは、テストインスタンスへの依存性注入や、テストインスタンスのカスタムの 初期化メソッド呼び出しなどがあります。
具体例は、MockitoExtension
や SpringExtension
のソースコードを参照してください。
5.6. 引数の解決
ParameterResolver
は、実行時に動的に引数を解決するための Extension
APIを定めています。
テストコンストラクタや @Test
, @RepeatedTest
, @ParameterizedTest
, @TestFactory
,
@BeforeEach
, @AfterEach
, @BeforeAll
, @AfterAll
メソッドが引数をもつ場合、
その引数は ParameterResolver
によって実行時に 解決 されなければいけません。
ParameterResolver
は、ビルトインのもの (TestInfoParameterResolver
参照) または
ユーザーが登録したもの のどちらかです。一般的に言うと、
引数は 名前、型、アノテーション、あるいはその組み合わせで解決されます。
具体例は、CustomTypeParameterResolver
や CustomAnnotationParameterResolver
のソースコードを参照してください。
JDK 9以前の そのため、
|
5.7. テストライフサイクルコールバック
以下のインターフェースは、テスト実行のライフサイクルにおける様々なタイミングでテストを拡張するための
APIを定めています。詳細は、以降の節にあるサンプルと、org.junit.jupiter.api.extension
パッケージにある
これらのインターフェースのJavadocを参照してください。
複数のExtension APIを実装する
拡張機能の開発者は、1つの拡張機能でこれらのインターフェースをいくつでも実装することができます。
具体例は、SpringExtension のソースコードを参照してください。
|
5.7.1. テスト実行前後のコールバック
BeforeTestExecutionCallback
と AfterTestExecutionCallback
は、
テストメソッドが実行される 直前 と 直後 に実行されるような振る舞いを追加したい場合の
Extension
API を定めています。実行時間の計測や、処理のトレースなどのユースケースに適しています。
もしも @BeforeEach
メソッドや @AfterEach
メソッドの 前後 に呼び出されるコールバックが
必要な場合は、代わりに BeforeEachCallback
や AfterEachCallback
を実装してください。
次の例は、テストメソッドの実行時間を計測してログ出力するために、
これらのコールバックを利用する方法を示しています。TimingExtension
は、
BeforeTestExecutionCallback
と AfterTestExecutionCallback
の両方を実装しています。
import java.lang.reflect.Method;
import java.util.logging.Logger;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
public class TimingExtension implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
private static final Logger logger = Logger.getLogger(TimingExtension.class.getName());
private static final String START_TIME = "start time";
@Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
getStore(context).put(START_TIME, System.currentTimeMillis());
}
@Override
public void afterTestExecution(ExtensionContext context) throws Exception {
Method testMethod = context.getRequiredTestMethod();
long startTime = getStore(context).remove(START_TIME, long.class);
long duration = System.currentTimeMillis() - startTime;
logger.info(() -> String.format("Method [%s] took %s ms.", testMethod.getName(), duration));
}
private Store getStore(ExtensionContext context) {
return context.getStore(Namespace.create(getClass(), context.getRequiredTestMethod()));
}
}
TimingExtensionTests
クラスは @ExtendWith
を使って TimingExtension
を登録しているので、テストを実行すると時間計測が有効になります。
@ExtendWith(TimingExtension.class)
class TimingExtensionTests {
@Test
void sleep20ms() throws Exception {
Thread.sleep(20);
}
@Test
void sleep50ms() throws Exception {
Thread.sleep(50);
}
}
以下は、TimingExtensionTests
が実行されたときに出力されるログの例です。
INFO: Method [sleep20ms] took 24 ms. INFO: Method [sleep50ms] took 53 ms.
5.8. 例外ハンドリング
TestExecutionExceptionHandler
は、テスト実行中に投げられた例外を扱うための
Extension
API を定めています。
次の例は、IOException
のすべてのインスタンスをもみ消し、
それ以外の例外は再スローするような拡張機能を示しています。
public class IgnoreIOExceptionExtension implements TestExecutionExceptionHandler {
@Override
public void handleTestExecutionException(ExtensionContext context, Throwable throwable)
throws Throwable {
if (throwable instanceof IOException) {
return;
}
throw throwable;
}
}
5.9. テストテンプレートに実行コンテキストを与える
@TestTemplate
メソッドは、TestTemplateInvocationContextProvider
が少なくとも1つ登録されている場合のみ実行されます。これらのプロバイダは、
TestTemplateInvocationContext
インスタンスの Stream
を返す責任をもちます。
各コンテキストは、カスタム表示名と @TestTemplate
メソッドの次の呼び出しだけで使われる
追加の拡張機能のリストを指定します。
次の例は、TestTemplateInvocationContextProvider
を実装して登録する方法と、
テストテンプレートを記述する方法を示しています。
@TestTemplate
@ExtendWith(MyTestTemplateInvocationContextProvider.class)
void testTemplate(String parameter) {
assertEquals(3, parameter.length());
}
public class MyTestTemplateInvocationContextProvider implements TestTemplateInvocationContextProvider {
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return true;
}
@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
return Stream.of(invocationContext("foo"), invocationContext("bar"));
}
private TestTemplateInvocationContext invocationContext(String parameter) {
return new TestTemplateInvocationContext() {
@Override
public String getDisplayName(int invocationIndex) {
return parameter;
}
@Override
public List<Extension> getAdditionalExtensions() {
return Collections.singletonList(new ParameterResolver() {
@Override
public boolean supportsParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return parameterContext.getParameter().getType().equals(String.class);
}
@Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return parameter;
}
});
}
};
}
}
この例では、テストテンプレートは2回実行されます。各実行の表示名は、実行コンテキストで指定された通り、
“foo” と “bar” になります。各実行では、メソッド引数を解決するために使われるカスタムの
ParameterResolver
を登録しています。 ConsoleLauncher
を使ったときの出力は、次のようになります。
└─ testTemplate(String) ✔ ├─ foo ✔ └─ bar ✔
TestTemplateInvocationContextProvider
拡張APIは、
テストクラスのインスタンスを異なるコンテキスト(例えば、異なる引数)で準備したり、
同じコンテキストで何回も呼び出したりするような、メソッドを繰り返し実行する様々なテストを
実装することを主目的としています。
繰り返しテスト や パラメーター化テスト が、
その機能を実現するためにこの拡張ポイントをどのように使っているか参考にしてください。
5.10. 拡張機能の状態を保持する
通常、拡張機能は一度だけしかインスタンス化されません。そのため、
拡張機能のある実行から次の実行までどのように状態を保持するのか?が問題となります。
ExtensionContext
APIは、まさにこの目的のために Store
を提供しています。
拡張機能は、値を Store
に保存しておいて、あとで取得することができます。
メソッドレベルのスコープで Store
を使用する例については、
TimingExtension
を参照してください。
テスト実行の間に ExtensionContext
に保存された値は、その外側の ExtensionContext
では利用できないことを覚えておくのは重要です。ExtensionContext
はネストされうるので、
内側の拡張コンテキストのスコープも制限されることがあります。
Store
経由で保存・取得するために使えるメソッドの詳細については、
関連する JavaDoc を参照してください。
ExtensionContext.Store.CloseableResource CloseableResource のインスタンスである場合は、その close()
メソッドが呼び出されて通知されます。
|
5.11. 拡張機能でサポートされるユーティリティ
junit-platform-commons
は、アノテーションやクラス、リフレクション、
クラスパスの探索処理に使える メンテナンスされた ユーティリティメソッドを含む
org.junit.platform.commons.support
というパッケージを提供しています。
TestEngine
や Extension
の作者は、JUnit Platformの振る舞いに合わせるために、
これらのメソッドを利用することが推奨されます。
5.11.1. アノテーションサポート
AnnotationSupport
は、アノテーションが付与された要素(例えば、パッケージやアノテーション、
クラス、インターフェース、コンストラクタ、メソッド、フィールド)を操作するstatic
なユーティリティメソッドを提供します。その中には、
ある要素に特定のアノテーションやメタアノテーションが付与されているかチェックしたり、
特定のアノテーションを探したり、クラスやフィールドからアノテーションの付与されたメソッドを
探したりするメソッドが含まれます。これらのメソッドのいくつかは、
アノテーションを探すために実装インターフェースやクラス階層を探索します。
さらなる詳細は、AnnotationSupport
のJavaDocを確認してください。
5.11.2. クラスサポート
ClassSupport
は、クラス(つまり、java.lang.Class
のインスタンス)を操作する
staticなユーティリティメソッドを提供します。詳細は、ClassSupport
のJavaDoc
を参照してください。
5.11.3. リフレクションサポート
ReflectionSupport
は、標準JDKのリフレクションとクラスロードの仕組みを強化する
staticなユーティリティメソッドを提供します。
その中には、指定された述語にマッチするクラスを求めてクラスパスを探索したり、
あるクラスをロードして新しいインスタンスを作成したり、メソッドを探して実行したりする
メソッドが含まれます。
これらのメソッドのいくつかは、マッチするメソッドを特定するためにクラス階層を探索します。
さらなる詳細は、ReflectionSupport
のJavaDocを確認してください。
5.12. ユーザーコードと拡張機能の相対的な実行順序
1つ以上のテストメソッドを含むテストクラスを実行する場合、ユーザーが指定するテストメソッドと ライフサイクルメソッドに加えて、多くの拡張機能コールバックが呼び出されます。次の図は、 ユーザーコードと拡張機能コードの相対的な実行順序を示しています。
ユーザーが提供するテストメソッドとライフサイクルメソッドはオレンジ色、 拡張機能が提供するコールバックコードは青色で示されています。灰色のボックスは、 単一のテストメソッドの実行を表し、テストクラス内のテストメソッド毎に繰り返されます。
次の表は、ユーザーコードと拡張機能コード の図の12ステップをさらに説明しています。
ステップ | インターフェース/アノテーション | 説明 |
---|---|---|
1 |
|
コンテナのすべてのテストが実行される前に実行される拡張機能のコード |
2 |
|
コンテナのすべてのテストが実行される前に実行されるユーザーコード |
3 |
|
各テストが実行される前に実行される拡張機能のコード |
4 |
|
各テストが実行される前に実行されるユーザーコード |
5 |
|
テストが実行される直前に実行される拡張機能のコード |
6 |
|
実際のテストメソッドとなるユーザーコード |
7 |
|
テストの間に投げられた例外をハンドリングするための拡張機能のコード |
8 |
|
テストが実行され、その例外ハンドラが処理された直後に実行される拡張機能のコード |
9 |
|
各テストが実行された後に実行されるユーザーコード |
10 |
|
各テストが実行された後に実行される拡張機能のコード |
11 |
|
コンテナのすべてのテストが実行された後に実行されるユーザーコード |
12 |
|
コンテナのすべてのテストが実行された後に実行される拡張機能のコード |
最も単純な場合は、実際のテストメソッドだけが実行されます (ステップ 6)。 ほかのすべてのステップは、ライフサイクルコールバックに対するユーザーコードや拡張機能コードの 有無によって省略可能です。様々なライフサイクルコールバックに関する詳細については、 各アノテーションや拡張機能に対する JavaDoc を参照してください。
6. JUnit 4からの移行
JUnit Jupiterのプログラミングモデルと拡張モデルは、Rule
や Runner
のようなJUnit 4の機能をネイティブにはサポートしていません。しかし、
ソースコードのメンテナがJUnit Jupiterへ移行するためにすべての既存テストやテスト拡張、
カスタムビルド基盤を書き換えることを求めているわけではありません。
代わりに、JUnit Platform上でJUnit 3またはJUnit 4ベースの既存テストを実行できる
ようにする JUnit Vintageテストエンジン を通して、なだらかな移行パスを提供しています。
JUnit Jupiter固有のクラスやアノテーションはすべて新設された org.junit.jupiter
パッケージ配下にあるため、JUnit 4とJUnit Jupiterが同時にクラスパスに含まれていても
コンフリクトは発生しません。そのため、既存のJUnit 4テストをJUnit Jupiter
テストと並行してメンテナンスしても安全です。さらに、JUnitチームはJUnit 4.x
系のメンテナンスとバグフィックスリリースを継続しているため、
開発者は自身のスケジュールに合わせてJUnit Jupiterに移行する十分な時間があります。
6.1. JUnit Platform上でJUnit 4テストを実行する
junit-vintage-engine
がテストランタイムパスに含まれていることを確認してください。
そうすれば、JUnit Platformランチャーが、JUnit 3およびJUnit 4のテストを自動的に
ピックアップしてくれます。
junit5-samples
リポジトリにあるサンプルプロジェクトを
参照して、GradleやMavenでどのように実現するか確認してください。
6.1.1. カテゴリのサポート
@Category
アノテーションの付与されたテストクラスやテストメソッドに対しては、
JUnit Vintageテストエンジン はカテゴリの完全修飾クラス名を該当テストのタグとみなします。
例えば、テストメソッドに @Category(Example.class)
アノテーションが付与されている場合、
"com.acme.Example"
でタグ付けされます。JUnit 4の Categories
ランナーと同様に、
この情報は実行するテストのフィルタリングに使われます (詳細は、テストを実行する 参照)。
6.2. 移行のヒント
既存のJUnit 4テストをJUnit Jupiterに移行するときに気をつけなければいけないことは、 次の通りです。
-
アノテーションは、
org.junit.jupiter.api
パッケージにあります。 -
アサーションは、
org.junit.jupiter.api.Assertions
にあります。 -
前提条件は、
org.junit.jupiter.api.Assumptions
にあります。 -
@Before
と@After
は、なくなりました。代わりに、@BeforeEach
と@AfterEach
を使ってください。 -
@BeforeClass
と@AfterClass
は、なくなりました。代わりに、@BeforeAll
と@AfterAll
を使ってください。 -
@Ignore
は、なくなりました。代わりに、@Disabled
を使ってください。 -
@Category
は、なくなりました。代わりに、@Tag
を使ってください。 -
@RunWith
は、なくなりました。@ExtendWith
に置き換えられました。 -
@Rule
と@ClassRule
は、なくなりました。@ExtendWith
に置き換えられました。 部分的なルールのサポートについては、次節を参照してください。
6.3. JUnit 4のルールの限定的なサポート
前述したように、JUnit JupiterはJUnit 4のルールをサポートしていませんし、 その予定もありません。しかし、JUnitチームは、多くの組織が(特に大きな組織ほど) カスタムルールを使ったJUnit 4のコードベースを保持していることを理解しています。 このような組織に段階的な移行パスを用意するため、JUnitチームはJUnit Jupiter でJUnit 4のルールをサポートすることを決めました。 このサポートはアダプタをベースにしており、JUnit Jupiterの拡張モデルと意味的に 互換性があるルールに限定されています。 例えば、テストの実行フローを完全に変えてしまうようなことがないものです。
JUnit Jupiterの junit-jupiter-migrationsupport
モジュールは、
今のところ次の3つの Rule
とそのサブクラスをサポートしています。
-
org.junit.rules.ExternalResource
(org.junit.rules.TemporaryFolder
も含む) -
org.junit.rules.Verifier
(org.junit.rules.ErrorCollector
も含む) -
org.junit.rules.ExpectedException
JUnit 4と同様に、Ruleアノテーションが付与されたフィールドとメソッドをサポートします。
これらのクラスレベルの拡張機能を使うことで、レガシーコードがもつ Rule
実装をJUnit 4のimport文も含めて 変更せずにそのままにしておく ことができます。
この限定的な形での Rule
サポートは、クラスレベルのアノテーション
org.junit.jupiter.migrationsupport.rules.EnableRuleMigrationSupport
を使って有効にすることができます。このアノテーションは、
VerifierSupport
, ExternalResourceSupport
, ExpectedExceptionSupport
のすべての移行サポート拡張を有効にするための 合成アノテーション になっています。
なお、JUnit 5に対する新しい拡張機能を開発するときには、JUnit 4 のルールベースのモデルではなく、JUnit Jupiterの拡張モデルを使ってください。
JUnit JupiterにおけるJUnit 4の Rule サポートは、今のところ
実験的な 機能です。詳細は、実験的なAPI
の表を確認してください。
|
7. Advanced Topics
7.1. JUnit Platform Launcher API
One of the prominent goals of JUnit 5 is to make the interface between JUnit and its programmatic clients – build tools and IDEs – more powerful and stable. The purpose is to decouple the internals of discovering and executing tests from all the filtering and configuration that’s necessary from the outside.
JUnit 5 introduces the concept of a Launcher
that can be used to discover, filter, and
execute tests. Moreover, third party test libraries – like Spock, Cucumber, and FitNesse
– can plug into the JUnit Platform’s launching infrastructure by providing a custom
TestEngine
.
The launcher API is in the junit-platform-launcher
module.
An example consumer of the launcher API is the ConsoleLauncher
in the
junit-platform-console
project.
7.1.1. Discovering Tests
Introducing test discovery as a dedicated feature of the platform itself will (hopefully) free IDEs and build tools from most of the difficulties they had to go through to identify test classes and test methods in the past.
Usage Example:
import static org.junit.platform.engine.discovery.ClassNameFilter.includeClassNamePatterns;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectPackage;
import org.junit.platform.launcher.Launcher;
import org.junit.platform.launcher.LauncherDiscoveryRequest;
import org.junit.platform.launcher.TestExecutionListener;
import org.junit.platform.launcher.TestPlan;
import org.junit.platform.launcher.core.LauncherConfig;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;
import org.junit.platform.launcher.listeners.SummaryGeneratingListener;
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(
selectPackage("com.example.mytests"),
selectClass(MyTestClass.class)
)
.filters(
includeClassNamePatterns(".*Tests")
)
.build();
Launcher launcher = LauncherFactory.create();
TestPlan testPlan = launcher.discover(request);
There’s currently the possibility to select classes, methods, and all classes in a package or even search for all tests in the classpath. Discovery takes place across all participating test engines.
The resulting TestPlan
is a hierarchical (and read-only) description of all engines,
classes, and test methods that fit the LauncherDiscoveryRequest
. The client can
traverse the tree, retrieve details about a node, and get a link to the original source
(like class, method, or file position). Every node in the test plan has a unique ID
that can be used to invoke a particular test or group of tests.
7.1.2. Executing Tests
To execute tests, clients can use the same LauncherDiscoveryRequest
as in the discovery
phase or create a new request. Test progress and reporting can be achieved by registering
one or more TestExecutionListener
implementations with the Launcher
as in the
following example.
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(
selectPackage("com.example.mytests"),
selectClass(MyTestClass.class)
)
.filters(
includeClassNamePatterns(".*Tests")
)
.build();
Launcher launcher = LauncherFactory.create();
// Register a listener of your choice
TestExecutionListener listener = new SummaryGeneratingListener();
launcher.registerTestExecutionListeners(listener);
launcher.execute(request);
There is no return value for the execute()
method, but you can easily use a listener to
aggregate the final results in an object of your own. For an example see the
SummaryGeneratingListener
.
7.1.3. Plugging in your own Test Engine
JUnit currently provides two TestEngine
implementations.
-
junit-jupiter-engine
: The core of JUnit Jupiter. -
junit-vintage-engine
: A thin layer on top of JUnit 4 to allow running vintage tests with the launcher infrastructure.
Third parties may also contribute their own TestEngine
by implementing the interfaces
in the junit-platform-engine module and registering their engine. By default, engine
registration is supported via Java’s java.util.ServiceLoader
mechanism. For example,
the junit-jupiter-engine
module registers its
org.junit.jupiter.engine.JupiterTestEngine
in a file named
org.junit.platform.engine.TestEngine
within the /META-INF/services
in the
junit-jupiter-engine
JAR.
HierarchicalTestEngine is a convenient abstract base implementation (used by
the junit-jupiter-engine ) that only requires implementors to provide the logic for
test discovery. It implements execution of TestDescriptors that implement the Node
interface, including support for parallel execution.
|
The
junit- prefix is reserved for TestEngines from the JUnit TeamThe JUnit Platform
|
7.1.4. Plugging in your own Test Execution Listener
In addition to the public Launcher
API method for registering test execution
listeners programmatically, by default custom TestExecutionListener
implementations
will be discovered at runtime via Java’s java.util.ServiceLoader
mechanism and
automatically registered with the Launcher
created via the LauncherFactory
. For
example, an example.TestInfoPrinter
class implementing TestExecutionListener
and
declared within the
/META-INF/services/org.junit.platform.launcher.TestExecutionListener
file is loaded and
registered automatically.
7.1.5. Configuring the Launcher
If you require fine-grained control over automatic detection and registration of test
engines and test execution listeners, you may create an instance of LauncherConfig
and
supply that to the LauncherFactory.create(LauncherConfig)
method. Typically an instance
of LauncherConfig
is created via the built-in fluent builder API, as demonstrated in
the following example.
LauncherConfig launcherConfig = LauncherConfig.builder()
.enableTestEngineAutoRegistration(false)
.enableTestExecutionListenerAutoRegistration(false)
.addTestEngines(new CustomTestEngine())
.addTestExecutionListeners(new CustomTestExecutionListener())
.build();
Launcher launcher = LauncherFactory.create(launcherConfig);
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectPackage("com.example.mytests"))
.build();
launcher.execute(request);
8. APIの進化
JUnit 5の主要な目的の1つは、JUnitが多くのプロジェクトで使われていたとしても、 メンテナがJUnitを進化させられるようにすることです。 JUnit 4では多くの部品が元々は内部用途で追加されましたが、 外部の拡張機能やツールの作者から使われることになりました。 そのせいで、JUnit 4の変更はとりわけ難しく、ときには不可能になりました。
JUnit 5がすべての公開インターフェースやクラス、メソッドに対して明確に定義された ライフサイクルを導入したのはこのためです。
8.1. APIバージョンとステータス
公開されているモジュールは <major>.<minor>.<patch>
というバージョン番号をもち、
すべての公開インターフェース、クラス、メソッドには @API Guardian プロジェクトの
@API アノテーションが付与されています。このアノテーションの status
属性には、
次のいずれかの値が設定されています。
ステータス | 説明 |
---|---|
|
JUnit自身以外のコードで使ってはならない。事前予告なしに削除されうる。 |
|
もう使うべきではない。次のマイナー (minor) リリースで削除されうる。 |
|
フィードバックがほしい実験的な新機能を意味する。注意して使うべき。 |
|
現在のメジャー (major) バージョンの 少なくとも 次のマイナー (minor)
リリースでは、後方互換性がない方法で変更されることがない機能を意味する。
削除予定になった場合は、まず最初に |
|
現在のメジャーバージョン ( |
@API
アノテーションが型に付与された場合、その型のすべての公開メンバーに適用されているとみなします。
個々のメンバーは、より低い安定度をもつ異なる status
属性を宣言することができます。
8.2. 実験的なAPI
次の表は、@API(status = EXPERIMENTAL)
で現在 実験的 と指定されたAPIを一覧しています。
これらのAPIを使う場合は注意してください。
Package Name | Type Name | Since |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8.3. 非推奨のAPI
次の表は、@API(status = DEPRECATED)
で現在 非推奨 と指定されたAPIを一覧しています。
非推奨になったAPIは今後のリリースで削除される可能性が高いため、可能な限り使わないようにしてください。
Package Name | Type Name | Since |
---|---|---|
|
|
|
|
|
|
8.4. @APIツールサポート
@API Guardian プロジェクトは、 @API アノテーションが付与されたAPIの提供者や利用者のために、
ツールによるサポートを計画しています。例えば、JUnitのAPIが @API
アノテーションの宣言にしたがって使われているかをチェックする手段を提供するなどです。
9. コントリビューター
GitHubで直接 現在のコントリビューター を参照してください。
10. リリースノート
リリースノートは、 こちら から参照できます。