この記事はJava Advent Calendar 2016の 22 日目です。昨日はcactaceaeさんの「MySQL on Fusion-IOのパフォーマンスを引き出すバッチパターン」でした。
タイトルの通り、JUnit 5 Users Guideの拙訳です。
最初はJUnit 5を使って何か面白い記事が書けないかと考えていましたが、なかなか記事を書く時間を取れなかったため、ユーザガイドの中途半端な翻訳で場を凌ぐことにしました。始めの3章しか書けていませんが、近いうちに最後まで仕上げたいと思います。
所々「こう書いた方が読み易いかなー?」と考えながら訳していったため、原文とは対応が取れていないところがあります。ご容赦ください。
また、「これは英語のままの方がわかり易いかも…?」と思いながらも日本語に無理やり翻訳した部分が多々ありますので、改善のアドバイスなどいただけると幸いです。
1. 概要
このドキュメントの目的は、以下のようなターゲットに対して包括的なリファレンスを提供することです。
- テストを記述するプログラマ
- エクステンションの作者
- エンジンの作成者(e.g. ビルドツールやIDEのベンダ)
1.1. JUnit 5とは
以前のバージョンのJUnitとは異なり、JUnit 5は3つのサブプロジェクト内のモジュールにより構成されています。
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit PlatformはJVM上でテスティングフレームワークを起動するための基礎を提供します。また同様に、このプラットフォーム上で実行されるテスティングフレームワークの開発のためのTestEngine
APIを定義します。さらに、コマンドラインからプラットフォームを起動し、GradleとMavenのプラグインを構築するConsoleLauncher
と、プラットフォーム上のTestEngine
を実行するためのJUnit 4ベースのRunner
を提供します。
JUnit Jupiterには、JUnit 5においてテストやエクステンションを記述するための新しいプログラミングモデルおよびエクステンションモデルが含まれています。このJupiterサブプロジェクトは、プラットフォーム上でJupiterにより記述されたテストを実行するためのTestEngine
を提供します。
JUnit Vintageはプラットフォーム上でJUnit 3およびJUnit 4により記述されたテストを実行するためのTestEngine
を提供します。
1.2. サポートされるJavaのバージョン
JUnit 5の利用には、Java 8のランタイムが必要です。しかし、以前のバージョンのJDKでコンパイルしたテストコードもそのまま利用することができます。
2. インストール
最終リリースおよびマイルストーンは、Maven Centralにデプロイされています。
スナップショットは、Sonatypeのスナップショットリポジトリの/org/junit配下にデプロイされています。
2.1. Dependencyメタデータ
2.1.1. JUnit Platform
-
Group ID:
org.junit.platform
-
Version:
1.0.0-M3
-
Artifact IDs:
junit-platform-commons
junit-platform-console
junit-platform-engine
junit-platform-gradle-plugin
junit-platform-launcher
junit-platform-runner
junit-platform-surefire-provider
2.1.2. JUnit Jupiter
-
Group ID:
org.junit.jupiter
-
Version:
5.0.0-M3
-
Artifact IDs:
junit-jupiter-api
junit-jupiter-engine
2.1.3. JUnit
-
Group ID:
org.junit.vintage
-
Version:
4.12.0-M3
-
Artifact ID:
junit-vintage-engine
2.2. JUnit Jupiterのサンプルプロジェクト
junit5-samples
リポジトリには、JUnit JupiterおよびJUnit Vintageによるサンプルプロジェクトがホストされています。build.gradle
およびpom.xml
はそれぞれ以下のプロジェクトにあります。
- Gradle:
junit5-gradle-consumer
- Maven :
junit5-maven-consumer
3. テストを記述する(Writing Tests)
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
パッケージ内にあります。
Annotation | Description |
---|---|
@Test | テストメソッドであることを示します。JUnit 4の@Test アノテーションと異なり、このアノテーションは属性を持ちません。JUnit Jupiterでのテスト拡張以降、それらに対しては専用のアノテーションがあります。 |
@TestFactory | 動的テストのファクトリメソッドであることを示します。 |
@DisplayName | テストクラス、テストメソッドのためのカスタム表示名(custom display name)を宣言します。 |
@BeforeEach | クラス内の各@Test メソッドの実行前に実行されるべきメソッドであることを示します。JUnit 4の@Before を引き継いでいます。 |
@AfterEach | クラス内の各@Test メソッドの実行後に実行されるべきメソッドであることを示します。JUnit 4の@After を引き継いでいます。 |
@BeforeAll | クラス内のすべての@Test メソッドの実行前に実行されるべきメソッドであることを示します。このメソッドはstatic でなければなりません。JUnit 4の@BeforeClass を引き継いでいます。 |
@AfterAll | クラス内のすべての@Test メソッドの実行後に実行されるべきメソッドであることを示します。このメソッドはstatic でなければなりません。JUnit 4の@AfterClass を引き継いでいます。 |
@Nested | ネストされた非staticなテストクラスであることを示します。Java言語の制約のため、@BeforeAll メソッドと@AfterAll メソッドは@Nested テストクラスでは使用できません。 |
@Tag | テストのフィルタリングをするためのタグの宣言に利用します。メソッド、クラスの両方に利用できます。TestNGのtest groupや、JUnit 4のCategoriesに類似しています。 |
@Disabled | テストクラスやテストメソッドが動作しないようにするために利用します。JUnit 4の@Ignore と似ています。 |
@ExtendWith | カスタム拡張(custom extension)を登録するために利用します。 |
3.2. 標準的なテストクラス
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("a failing test");
}
@Test
@Disabled("for demonstration purposes")
void skippedTest() {
// not executed
}
@AfterEach
void tearDown() {
}
@AfterAll
static void tearDownAll() {
}
}
Note: テストクラス、テストメソッドは
public
である必要はありません。
3.3 表示名(Display Names)
テストクラスおよびテストメソッドは、Runnerやレポートで表示するためのカスタム表示名を宣言することができます。カスタム表示名には、空白文字(space)、特殊文字、絵文字を利用することができます。
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
// カスタム表示名に空白文字を利用できることを示すために英語のままにしています。
@DisplayName("A special test case")
class DisplayNameDemo {
@Test
@DisplayName("Custom test name containing spaces")
void testWithDisplayNameContainingSpaces() {
}
@Test
@DisplayName("╯°□°)╯")
void testWithDisplayNameContainingSpecialCharacters() {
}
@Test
@DisplayName("😱")
void testWithDisplayNameContainingEmoji() {
}
}
3.4. アサーション(Assertions)
JUnit Jupiterには、JUnit 4の持つ多くのアサーションメソッドが付属しています。それに加えて、(Java SE 8以降で利用できる)ラムダ式を利用するために役立つものがいくつか追加されています。
すべてのJUnit Jupiterアサーションは、org.junit.jupiter.Assersions
クラスのstaticメソッドです。
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.expectThrows;
import org.junit.jupiter.api.Test;
class AssertionsDemo {
@Test
void standardAssertions() {
assertEquals(2, 2);
assertEquals(4, 4, "この最後のパラメータは、オプションのアサーションメッセージです。");
assertTrue(2 == 2, () -> "アサーションメッセージは遅延評価することができます。"
+ "−−−複雑なメッセージを無駄に構成することを回避するために。");
}
@Test
void groupedAssertions() {
// グループ化されたアサーションは、すべてのアサーションが実行され、
// 失敗した場合は同時にレポートされる
assertAll("address",
() -> assertEquals("John", address.getFirstName()),
() -> assertEquals("User", address.getLastName())
);
}
@Test
void exceptionTesting() {
Throwable exception = expectThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("何かしらのメッセージ");
});
assertEquals("何かしらのメッセージ", exception.getMessage());
}
}
3.5. アサンプション(Assumptions)
JUnit Jupiterには、JUnit 4が提供するassumptionメソッドのサブセットが付属しており、ラムダ式で使用するのに適しています。
すべてのJUnit Jupiterのassumptionは、org.junit.jupiter.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;
public class AssumptionsDemo {
@Test
void testOnlyOnCiServer() {
assumeTrue("CI".equals(System.getenv("ENV")));
// 残りのテスト
}
@Test
void testOnlyOnDeveloperWorkstation() {
assumeTrue("DEV".equals(System.getenv("ENV")),
() -> "Aborting test: 開発者のコンピュータではありません。");
// 残りのテスト
}
@Test
void testInAllEnvironments() {
assumingThat("CI".equals(System.getenv("ENV")),
() -> {
// この中のアサーションは、CIサーバのみで実行される
assertEquals(2, 2);
});
// この中のアサーションは、すべての環境で実行される
assertEquals("a string", "a string");
}
}
3.6. 動作しないテスト(Disabling Test)
以下は動作しないテストケースです。
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled
class DisabledClassDemo {
@Test
void testWillBeSkipped() {
}
}
以下のテストケースは、動作しないテストメソッドを持ちます。
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
class DisabledTestsDemo {
@Disabled
@Test
void testWillBeSkipped() {
}
@Test
void testWillBeExecuted() {
}
}
3.7. タグ付けおよびフィルタリング
テストクラスおよびテストメソッドはダグ付けすることができる。これらのタグは、テストの発見や実行のためのフィルタとして利用できる。
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
// 複数のタグを付けることが可能
@Tag("fast")
@Tag("model")
class TaggingDemo {
@Test
@Tag("taxes")
void testingTaxCalculation() {
}
}
3.8. ネストされたテスト(Nested Tests)
ネストされたテストは、テスト作成者に対してテストグループ同士の関係のためのより高い表現能力を与える。
以下はちょっとした例(elaborate example)です。
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("スタック")
class TestingAStackDemo {
Stack<Object> stack;
@Test
@DisplayName("Stackのインスタンスを生成")
void isInstantiatedWithNew() {
new Stack<>();
}
@Nested
@DisplayName("生成直後")
class WhenNew {
@BeforeEach
void createNewStack() {
stack = new Stack<>();
}
@Test
@DisplayName("空")
void isEmpty() {
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("popを行うとEmptyStackExceptionをスローする")
void throwsExceptionWhenPopped() {
assertThrows(EmptyStackException.class, () -> stack.pop());
}
@Test
@DisplayName("peekを行うとEmptyStackExceptionをスローする")
void throwsExceptionWhenPeeked() {
assertThrows(EmptyStackException.class, () -> stack.peek());
}
@Nested
@DisplayName("1つの要素をpushした後")
class AfterPushing {
String anElement = "要素";
@BeforeEach
void pushAnElement() {
stack.push(anElement);
}
@Test
@DisplayName("もはや空ではない")
void isEmpty() {
assertFalse(stack.isEmpty());
}
@Test
@DisplayName("popした要素を返すとスタックは空になる")
void returnElementWhenPopped() {
assertEquals(anElement, stack.pop());
assertTrue(stack.isEmpty());
}
@Test
@DisplayName("peekした要素を返してもスタックは空にならない")
void returnElementWhenPeeked() {
assertEquals(anElement, stack.peek());
assertFalse(stack.isEmpty());
}
}
}
}
Note: 内部クラス(非staticなネストされたクラス)のみ
@Nested
クラスにすることができます。任意の深さでネストが可能で、それらの内部クラスはテストクラスファミリの@BeforeAll
および@AfterAll
以外のすべてのメンバを利用できます。(Javaにおいて内部クラスのstatic
メンバは許されないため、@BeforeAll
および@AfterAll
は利用できません)
3.9. コンストラクタとメソッドのためのDI(Dependency Injection)
以前のバージョンのJUnitでは(少なくとも標準のRunner
の実装においては)、テストコンストラクタやテストメソッドはパラメータを持つことはできませんでした。JUnit Jupiterにおける大きな変更の一つとして、テストコンストラクタとテストメソッドの両方において、パラメータを持つことができるようになっています。これにより、より高い柔軟性を持ち、コンストラクタやメソッドに対してDependency Injectionが可能になります。
ParameterResolver
では、実行時に動的にパラメータを解決したいテスト拡張のためのAPIを定義している。
テストコンストラクタや@Test
、@TestFactory
、@BeforeEach
、@AfterEach
、@BeforeAll
、@AfterAll
メソッドはパラメータを持つことができます。それらのパラメータは登録されたParameterResolver
により実行時に解決されなければなりません。
これらは現在の自動的に登録される2つの組み込みリゾルバです。
-
TestInfoParameterResolver
: メソッドがTestInfo
型のパラメータを持つ場合、TestInfoParameterResolver
は現在のテストに関連付けられたTestInfo
のインスタンスをパラメータの値として提供する。TestInfo
はテストの表示名、テストクラス、テストメソッド、関連するタグなど、現在のテストに関する情報を確認する時に利用できる。表示名はテストクラスやテストメソッドの名前ようなコードに直接記述された名前であるか、もしくは@DisplayName
により設定された名前です。
TestInfo
はJUnit 4のTestName
ルールの差し当りの代替として機能します。以下が利用例です。
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;
class TestInfoDemo {
@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() {
}
}
-
TestReporterParameterResolver
: パラメータがTestReporter
型の場合、TestReporterParameterResolver
はTestReporter
のインスタンス提供します。このTestReporter
は現行のテストに関するデータをレポートに追加することができます。このデータはTestExecuterListener
で使用されます。reportingEntryPublished()
を呼び出すことによりIDEでの表示、レポートに含めることができます。
JUnit Jupiterでは、JUnit 4の標準出力や標準エラーに情報を出力する際にはTestReport
を利用するべきです。@RunWith(JUnitPlatform.class)
を使用すると、すべてのレポートのエントリが標準出力にい出力されます。
import java.util.HashMap;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestReporter;
class TestReporterDemo {
@Test
void reportSingleValue(TestReporter testReporter) {
testReporter.publishEntry("a key", "a value");
}
@Test
void reportSeveralValues(TestReporter testReporter) {
HashMap<String, String> values = new HashMap<>();
values.put("user name", "dk38");
values.put("award year", "1974");
testReporter.publishEntry(values);
}
}
Note:
@ExtendWith
により適切な拡張を登録することで、他のパラメータリゾルバを明示的に有効にする必要があります。
ParameterResolver
をカスタムするの例のためにMockitoExtension
をチェックアウトします。本番環境での運用を目的としたものではありませんが、拡張モデルとパラメータ解決プロセスの簡潔さと表現力を示しています。MyMockitoTest
は@BeforeEach
と@Test
メソッドにMockitoのモックをインジェクトする方法を示しています。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import com.example.Person;
import com.example.mockito.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class MyMockitoTest {
@BeforeEach
void init(@Mock Person person) {
when(person.getName()).thenReturn("Dilbert");
}
@Test
void simpleTestWithInjectedMock(@Mock Person person) {
assertEquals("Dilbert", person.getName());
}
}
3.10. インタフェースのデフォルトメソッド
JUnit Jupiterでは、インタフェースのデフォルドメソッドで@Test
、@TestFactory
、@BeforeEach
、@AfterEach
を宣言することができます。
この機能の応用として、インタフェースの制約に関するテストを書くことができます。
例えば、次のように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 returnsPositiveNumberComparedToSmallerValue() {
T value = createValue();
T smallerValue = createSmallerValue();
assertTrue(value.compareTo(smallerValue) > 0);
}
@Test
default void returnsNegativeNumberComparedToSmallerValue() {
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.11. 動的テスト(Dynamic Tests)
JUnit Jupiterにおける標準の@Test
アノテーションの機能は、JUnit 4の@Test
アノテーションと非常によく似ています。JUnit JupiterにおいてもJUnit 4においても、テストケースのメソッドの実装に記述します。これらのテストケースは、コンパイル時に完全に記述され、実行時に挙動が変更されない、という意味では静的です。Assumptions
は動的な振る舞いに関する基本的な形式を提供しますが、意図的に表現力が限定されています。
JUnit Jupiterには、これらの標準的なテストに加えて、まったく新しい形式のテストが導入されました。
@TestFactory
アノテーションが付与されたファクトリメソッドによって実行時に生成される動的なテストです。
@Test
メソッドとは対照的に、@TestFactory
メソッド自身はテストケースではなく、テストケースのためのファクトリです。
したがって、動的なテストはファクトリによって生成されます。技術的な話をすると、@TestFactory
メソッドはDynamicTest
インスタンスのストリーム、コレクション、イテラブル、イテレータを返す必要があります。
これらのDynamicTest
インスタンスは遅延実行されるため、テストケースの動的生成や非決定的生成さえも可能になります。
@Test
と同様に、@TestFacotry
メソッドはprivate
やstatic
であってはならず、ParameterResolver
によって解決されるパラメータをオプションとして宣言することができます。
DynamicTest
は実行時に生成されるテストケースです。これは表示名とExecutable
で構成されています。Executable
は@FunctioanlInterface
で、動的テストはメソッド参照やラムダ式を用いて実装することができる。
動的テストのライフサイクル:
動的テストの実行ライフサイクルは、標準の@Test
の場合とはかなり異なります。具体的には、ライフサイクルは動的テストのためのコールバックを行いません。これは、@BeforeEach
メソッドと@AfterEach
メソッドとそれに対応する拡張コールバックは動的テストでは実行されないということです。 つまり、ダイナミックテストのラムダ式内のテストインスタンスからフィールドにアクセスする場合、これらのフィールドは同じ@TestFactory
メソッドで生成された動的テストの実行間のコールバックメソッドまたは拡張によってリセットされません。
JUnit Jupiter 5.0.0-M3以降、動的テストは常にファクトリメソッドにより作成されるべきです。ただし、これは後のリリースで提供されるであろうファクトリにより達成されます。
3.11.1. 動的テストの例
以下のDynamicTestDemo
クラスでは、テストファクトリと動的テストの例をいくつか示しています。
最初のメソッドは不正な戻り値の型を返します。コンパイル時には不正な戻り値の型が検出されず、実行時にJUnitExceptionがスローされます。
次の5つのメソッドは、DynamicTest
インスタンスのCollection
、Iterable
、Iterator
、Stream
の生成を示す非常に簡単な例です。
これらの例のほとんどは実際に動的な振る舞いを示すものではなく、原則としてサポートされている戻り値型を単に示しています。
ただし、dynamicTestsFromStream()
およびdynamicTestsFromIntStream()
は、指定された文字列または入力範囲の範囲に対して簡単に動的テストを生成できることを示しています。
最後の例は自然な真に動的なものです。
generateRandomNumberOfTests()
は、乱数を生成するIterator
、表示名ジェネレータ、およびテスト実行プログラムを実装し、3つすべてをDynamicTest.stream()
に式渡しています。 generateRandomNumberOfTests()
の非決定論的な振る舞いは、テストの再現性と矛盾しますので、注意して使用する必要がありますが、動的テストの表現力とパワーを実証することができています。
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
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.Consumer;
import java.util.function.Function;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.TestFactory;
class DynamicTestsDemo {
// JUnitExceptionが発生する
@TestFactory
List<String> dynamicTestsWithInvalidReturnType() {
return Arrays.asList("Hello");
}
@TestFactory
Collection<DynamicTest> dynamicTestsFromCollection() {
return Arrays.asList(
dynamicTest("1つ目の動的テスト", () -> assertTrue(true)),
dynamicTest("2つ目の動的テスト", () -> assertEquals(4, 2 * 2))
);
}
@TestFactory
Iterable<DynamicTest> dynamicTestsFromIterable() {
return Arrays.asList(
dynamicTest("3つ目の動的テスト", () -> assertTrue(true)),
dynamicTest("4つ目の動的テスト", () -> assertEquals(4, 2 * 2))
);
}
@TestFactory
Iterator<DynamicTest> dynamicTestsFromIterator() {
return Arrays.asList(
dynamicTest("5つ目の動的テスト", () -> assertTrue(true)),
dynamicTest("6つ目の動的テスト", () -> assertEquals(4, 2 * 2))
).iterator();
}
@TestFactory
Stream<DynamicTest> dynamicTestsFromStream() {
return Stream.of("A", "B", "C").map(
str -> dynamicTest("test" + str, () -> { /* ... */ }));
}
@TestFactory
Stream<DynamicTest> dynamicTestsFromIntStream() {
// 最初の10個の偶数に関するテストを生成する
return IntStream.iterate(0, n -> n + 2).limit(10).mapToObj(
n -> dynamicTest("test" + n, () -> assertTrue(n % 2 == 0)));
}
@TestFactory
Stream<DynamicTest> generateRandomNumberOfTests() {
// 7の倍数が出現するまで、0から100までのランダムな正整数を生成(7の倍数は含まれない)
Iterator<Integer> inputGenerator = new Iterator<Integer>() {
Random random = new Random();
int current;
@Override
public boolean hasNext() {
current = random.nextInt(100);
return current % 7 != 0;
}
@Override
public Integer next() {
return current;
}
};
// 以下のような表示名生成する: input:5、input:37、input:85 etc.
Function<Integer, String> displayNameGenerator = (input) -> "input:" + input;
// 現在の入力値に対するテストを実行する
Consumer<Integer> testExecutor = (input) -> assertTrue(input % 7 != 0);
// 動的テストのストリームを返す
return DynamicTest.stream(inputGenerator, displayNameGenerator, testExecutor);
}
}