1. 概要

テストするとき、一時ファイルにアクセスする必要があることがよくあります。 ただし、これらのファイルの作成と削除を自分で管理するのは面倒な場合があります。

このクイックチュートリアルでは、JUnit5がTempDirectory拡張機能を提供することでこれをどのように軽減するかを見ていきます。

JUnitを使用したテストの詳細なガイドについては、優れた JUnit5ガイドをご覧ください。

2. TempDirectory拡張機能

バージョン5.4.2以降、JUnit5はTempDirectory拡張機能を提供します。 ただし、公式にはこれはまだ実験的機能であり、JUnitチームにフィードバックを提供することをお勧めします。

後で説明するように、この拡張機能を使用して、個々のテストまたはテストクラス内のすべてのテスト用の一時ディレクトリを作成およびクリーンアップできます。

通常、拡張機能を使用する場合、@ExtendWithアノテーションを使用してJUnit5テスト内から登録する必要があります。 ただし、これは、組み込みでデフォルトで登録されているTempDirectory拡張機能では必要ありません。

3. Mavenの依存関係

まず、例に必要なプロジェクトの依存関係を追加しましょう。

メインのJUnit5ライブラリjunit-jupiter-engineとは別に、junit-jupiter-apiライブラリも必要です。

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

いつものように、 MavenCentralから最新バージョンを入手できます。

これに加えて、junit-jupiter-params依存関係も追加する必要があります。

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

ここでも、 MavenCentralで最新バージョンを見つけることができます。

4. @TempDirアノテーションの使用

TempDirectory拡張機能を使用するには、@TempDirアノテーションを使用する必要があります。 このアノテーションは、次の2つのタイプでのみ使用できます。

  • java.nio.file.Path
  • java.io.File

実際、別のタイプで使用しようとすると、org.junit.jupiter.api.extension.ParameterResolutionExceptionがスローされます。

次に、この注釈を使用するいくつかの異なる方法を調べてみましょう。

4.1. メソッドパラメータとしての@TempDir

まず、@TempDirアノテーションが付けられたパラメーターを単一のテストメソッドに注入する方法を見てみましょう。

@Test
void givenTestMethodWithTempDirectory_whenWriteToFile_thenContentIsCorrect(@TempDir Path tempDir) 
  throws IOException {
    Path numbers = tempDir.resolve("numbers.txt");

    List<String> lines = Arrays.asList("1", "2", "3");
    Files.write(numbers, lines);

    assertAll(
      () -> assertTrue("File should exist", Files.exists(numbers)),
      () -> assertLinesMatch(lines, Files.readAllLines(numbers)));
}

ご覧のとおり、テストメソッドは一時ディレクトリtempDirnumbers.txtというファイルを作成して書き込みます。

次に、ファイルが存在し、コンテンツが最初に書き込まれたものと一致することを確認します。 本当に素晴らしくてシンプルです!

4.2. インスタンスフィールドの@TempDir

この次の例では、 @TempDir アノテーションを使用して、テストクラスのフィールドにアノテーションを付けます。

@TempDir
File anotherTempDir;

@Test
void givenFieldWithTempDirectoryFile_whenWriteToFile_thenContentIsCorrect() throws IOException {
    assertTrue("Should be a directory ", this.anotherTempDir.isDirectory());

    File letters = new File(anotherTempDir, "letters.txt");
    List<String> lines = Arrays.asList("x", "y", "z");

    Files.write(letters.toPath(), lines);

    assertAll(
      () -> assertTrue("File should exist", Files.exists(letters.toPath())),
      () -> assertLinesMatch(lines, Files.readAllLines(letters.toPath())));
}

今回は、一時ディレクトリにjava.io.Fileを使用します。 繰り返しますが、いくつかの行を書き込み、それらが正常に書き込まれたことを確認します。

この単一の参照を他のテストメソッドで再度使用する場合、各テストは独自の一時ディレクトリを使用します。

4.3. 共有一時ディレクトリ

テストメソッド間で一時ディレクトリを共有したい場合があります

これを行うには、フィールドstaticを宣言します。

@TempDir
static Path sharedTempDir;

@Test
@Order(1)
void givenFieldWithSharedTempDirectoryPath_whenWriteToFile_thenContentIsCorrect() throws IOException {
    Path numbers = sharedTempDir.resolve("numbers.txt");

    List<String> lines = Arrays.asList("1", "2", "3");
    Files.write(numbers, lines);

    assertAll(
        () -> assertTrue("File should exist", Files.exists(numbers)),
        () -> assertLinesMatch(lines, Files.readAllLines(numbers)));
}

@Test
@Order(2)
void givenAlreadyWrittenToSharedFile_whenCheckContents_thenContentIsCorrect() throws IOException {
    Path numbers = sharedTempDir.resolve("numbers.txt");

    assertLinesMatch(Arrays.asList("1", "2", "3"), Files.readAllLines(numbers));
  }

ここで重要な点は、2つのテストメソッド間で共有する静的フィールドsharedTempDirを使用することです。

最初のテストでは、numbers.txtというファイルにいくつかの行を再度書き込みます。 次に、次のテストでファイルとコンテンツがすでに存在することを確認します。

また、テストの順序 @Order アノテーションを介して適用し、動作が常に一貫していることを確認します。

5. ガッチャ

次に、TempDirectory拡張機能を使用するときに注意する必要のある微妙な点をいくつか確認しましょう。

5.1. 創造

好奇心旺盛な読者は、これらの一時ファイルが実際にどこで作成されているのか疑問に思うでしょう。

内部的には、JUnit TemporaryDirectoryクラスはFiles.createTempDirectory(String prefix)メソッドを利用します。 同様に、このメソッドはデフォルトのシステム一時ファイルディレクトリを利用します。

これは通常、環境変数TMPDIRで指定されます。

TMPDIR=/var/folders/3b/rp7016xn6fz9g0yf5_nj71m00000gn/T/

たとえば、一時ファイルの場所は次のようになります。

/var/folders/3b/rp7016xn6fz9g0yf5_nj71m00000gn/T/junit5416670701666180307/numbers.txt

一方、一時ディレクトリを作成できない場合は、必要に応じてExtensionConfigurationExceptionがスローされます。 または、前述のように、ParameterResolutionException

5.2. 消す

テストメソッドまたはクラスの実行が終了し、一時ディレクトリがスコープ外になると、 JUnitフレームワークは、そのディレクトリ内のすべてのファイルとディレクトリ、そして最後に一時ディレクトリ自体を再帰的に削除しようとします。

この削除フェーズ中に問題が発生した場合、 IOException がスローされ、テストまたはテストクラスは失敗します。

6. 結論

要約すると、このチュートリアルでは、JUnit5によって提供されるTempDirectory拡張機能について説明しました。

まず、拡張機能を紹介することから始め、それを使用するために必要なMavenの依存関係を学びました。 次に、単体テスト内から拡張機能を使用する方法のいくつかの例を確認しました。

最後に、一時ファイルが作成される場所や削除中に何が起こるかなど、いくつかの落とし穴を調べました。

いつものように、記事の完全なソースコードは、GitHubから入手できます。