web-dev-qa-db-ja.com

JUnit 5のExternalResourceとTemporaryFolderに相当するものは何ですか?

JUnit 5ユーザーガイド によると、JUnit Jupiterは、移行を支援するために、一部のJUnit4ルールに下位互換性を提供します。

上記のように、JUnitJupiterはJUnit4ルールをネイティブにサポートしていません。ただし、JUnitチームは、多くの組織、特に大規模な組織では、カスタムルールを含む大規模なJUnit4コードベースを使用する可能性が高いことを認識しています。これらの組織にサービスを提供し、段階的な移行パスを有効にするために、JUnitチームは、JUnitJupiter内で逐語的にJUnit4ルールの選択をサポートすることを決定しました。

ガイドはさらに、ルールの1つは ExternalResource であり、これは TemporaryFolder の親であると述べています。

ただし、残念ながら、このガイドでは、移行パスとは何か、または新しいJUnit5テストを作成する場合の同等のパスについては説明していません。では、何を使うべきでしょうか?

15
Thunderforge

JUnit 5.4には、テストで一時ディレクトリを処理するための拡張機能が組み込まれています。

@org.junit.jupiter.api.io.TempDirアノテーションは、ライフサイクル内のクラスフィールドまたはパラメータにアノテーションを付けるために使用できます(例:@BeforeEach)またはタイプFileまたはPathのテストメソッド。

import org.junit.jupiter.api.io.TempDir;

@Test
void writesContentToFile(@TempDir Path tempDir) throws IOException {
    // arrange
    Path output = tempDir
            .resolve("output.txt");

    // act
    fileWriter.writeTo(output.toString(), "test");

    // assert
    assertAll(
            () -> assertTrue(Files.exists(output)),
            () -> assertLinesMatch(List.of("test"), Files.readAllLines(output))
    );
}

これについての詳細は、私のブログ投稿で読むことができます。ここでは、この組み込み拡張機能の利用に関するいくつかの例を見つけることができます。 https://blog.codeleak.pl/2019/03/temporary-directories-in- junit-5-tests.html

4
Rafal Borowiec

JUnit5のTemporaryFolderExtensionの作者による興味深い記事

そして

githubの彼のコードリポジトリ

JUnit5.0.0は現在一般リリースされているので、実験的なものを本番環境に対応させることに注意を向けることを期待しましょう。

一方、TemporaryFolderルールは引き続きJUnit5で機能するようです docs

これを使って:

@EnableRuleMigrationSupport
public class MyJUnit5Test {

この:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-migrationsupport</artifactId>
    <version>5.0.0</version>
</dependency>
5
Adam

そのためのドキュメントはまだ作成中です プルリクエスト#66 を参照してください。

4
Nicolai

私が理解している限り、ExternalResourceからJUnit5の同等のものへの1対1のマッピングはあり得ません。概念はちょうど適合しません。 JUnit4では、ExternalResourceは基本的にbeforeafterコールバックを提供しますが、ルール内では、beforeafterが実際に何を意味するかを制御することはできません。 @Ruleまたは@ClassRuleと一緒に使用できます。

JUnit5では、拡張機能は特定の 拡張ポイント にフックするように定義されているため、「when」は適切に定義されています。

概念のもう1つの違いは、JUnit4ルールに状態を含めることはできますが、JUnit5拡張機能に状態を含めることはできないということです。代わりに、すべての状態は 実行コンテキスト に移動する必要があります。

それにもかかわらず、ここに私が持ってきたオプションがあります。ここで、beforeafterは各テストメソッドに関連しています。

public abstract class ExternalResourceExtension 
  implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception {
        before(context);
    }

    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        after(context);
    }

    protected abstract void before(ExtensionContext context);

    protected abstract void after(ExtensionContext context);
}
3
simomat

一時フォルダには、 _@TempDir_ という方法で解決策があります。しかし、一般的にExternalResourcesの背後にある考え方はどうですか?おそらく、モックデータベース、モックHTTP接続、またはサポートを追加したいその他のカスタムリソース用ですか?

答えは、 _@RegisterExtension_ アノテーションを使用して、非常によく似たものを実現できることがわかりました。

使用例:

_/**
 * This is my resource shared across all tests
 */
@RegisterExtension
static final MyResourceExtension MY_RESOURCE = new MyResourceExtension();

/**
 * This is my per test resource
 */
@RegisterExtension
final MyResourceExtension myResource = new MyResourceExtension();

@Test
void test() {
    MY_RESOURCE.doStuff();
    myResource.doStuff();
}
_

そして、これがMyResourceExtensionの基本的な足場です。

_public class MyResourceExtension implements BeforeAllCallback, AfterAllCallback,
        BeforeEachCallback, AfterEachCallback {

    private SomeResource someResource;

    private int referenceCount;

    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        beforeEach(context);
    }

    @Override
    public void afterAll(ExtensionContext context) throws Exception {
        afterEach(context);
    }

    @Override
    public void beforeEach(ExtensionContext context) throws Exception {
        if (++referenceCount == 1) {
            // Do stuff in preparation
            this.someResource = ...;
        }
    }

    @Override
    public void afterEach(ExtensionContext context) throws Exception {
        if (--referenceCount == 0) {
            // Do stuff to clean up
            this.someResource.close();
            this.someResource = null;
        }
    }

    public void doStuff() {
        return this.someResource.fooBar();
    }

}
_

もちろん、これをすべて抽象クラスとしてまとめて、MyResourceExtensionprotected void before()protected void after()などを実装させることもできますが、それは私です。簡潔にするためにそれを省略します。

0
antak