The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
Back to Guides

アプリケーションのテスト

Quarkusアプリケーションのテスト方法について説明します。このガイドでは、以下の内容について説明します。

  • JVM モードでのテスト

  • ネイティブモードでのテスト

  • テストへのリソースの注入

1. 前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 11+ がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.8.6

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

  • 入門ガイドに掲載されている、完了済のGreeterアプリケーション

2. アーキテクチャ

このガイドでは、入門ガイドの一部として作成された最初のテストを拡張します。テストへのインジェクションと、ネイティブ実行可能ファイルをテストする方法もカバーしています。

Quarkus は継続テストをサポートしていますが、これについては 継続テストガイド で説明しています。

3. ソリューション

次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。

Gitリポジトリをクローンする: git clone https://github.com/quarkusio/quarkus-quickstarts.git 、または アーカイブ をダウンロードします。

ソリューションは getting-started-testing ディレクトリ にあります。

このガイドでは、 getting-started ディレクトリーの完成したアプリケーションをすでに持っていることを前提としています。

4. JVM モードでの HTTP ベースのテストの要約

「はじめに」のサンプルから始めた場合は、正しいツールマップの設定を含めて、すでにテストが完了しているはずです。

ビルドファイルには、2 つのテスト依存関係が表示されます。

Maven
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <scope>test</scope>
</dependency>
Gradle
dependencies {
    testImplementation("io.quarkus:quarkus-junit5")
    testImplementation("io.rest-assured:rest-assured")
}

quarkus-junit5 は、テストフレームワークを制御する @QuarkusTest アノテーションを提供するため、テストには必須です。 rest-assured は必須ではありませんが、HTTP エンドポイントをテストするのに便利な方法です。

JUnit 5を使用しているので、 Surefire Maven Pluginのバージョンを設定する必要があります。デフォルトのバージョンはJUnit 5をサポートしていない為です。

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire-plugin.version}</version>
    <configuration>
       <systemPropertyVariables>
          <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
          <maven.home>${maven.home}</maven.home>
       </systemPropertyVariables>
    </configuration>
</plugin>

また、テストが正しいログマネージャーを使用するように java.util.logging.manager システムプロパティーを設定し、${maven.home}/conf/settings.xml からのカスタム設定が (あれば) 適用されるように maven.home を設定します。

プロジェクトには簡単なテストも含まれているはずです:

package org.acme.getting.started.testing;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import java.util.UUID;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class GreetingResourceTest {

    @Test
    public void testHelloEndpoint() {
        given()
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("hello"));
    }

    @Test
    public void testGreetingEndpoint() {
        String uuid = UUID.randomUUID().toString();
        given()
          .pathParam("name", uuid)
          .when().get("/hello/greeting/{name}")
          .then()
            .statusCode(200)
            .body(is("hello " + uuid));
    }

}

このテストはHTTPを使用して、RESTエンドポイントを直接テストします。テストが実行されると、テストが実行される前にアプリケーションが開始されます。

4.1. テストポートの制御

Quarkusはデフォルトではポート 8080 をリッスンしますが、テストを実行する場合はデフォルトで 8081 をリッスンします。これにより、アプリケーションを並行して実行しながらテストを実行することができます。

テストポートの変更

application.propertiesquarkus.http.test-port を設定することで、を HTTP 用にテストで使われるポートを設定出来、 quarkus.http.test-ssl-port を設定することで HTTPS 用にテストで使用するポートを設定することが出来ます。

quarkus.http.test-port=8083
quarkus.http.test-ssl-port=8446

0 を使用すると、(オペレーティングシステムによって割り当てられた)ランダムなポートが使用されることになります。

Quarkusはまた、テストを実行する前にRestAssuredによって使用されるデフォルトのポートを更新するRestAssuredインテグレーションも提供しているため、追加の設定は必要ありません。

4.2. HTTP インタラクションタイムアウトの制御

テストで REST Assured を使用する場合、接続と応答のタイムアウトは 30 秒に設定されます。この設定は quarkus.http.test-timeout プロパティーでオーバーライドできます:

quarkus.http.test-timeout=10s

4.3. URI の挿入

URLをテストに直接注入することも可能で、別のクライアントを使用するのが簡単になります。これは @TestHTTPResource アノテーションで行います。

静的なリソースをロードするための簡単なテストを書いてみましょう。まず、シンプルなHTMLファイルを src/main/resources/META-INF/resources/index.html に作成します:

<html>
    <head>
        <title>Testing Guide</title>
    </head>
    <body>
        Information about testing
    </body>
</html>

これが正しく提供されているかどうかを確認するための簡単なテストを作成します:

package org.acme.getting.started.testing;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import io.quarkus.test.common.http.TestHTTPResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class StaticContentTest {

    @TestHTTPResource("index.html") (1)
    URL url;

    @Test
    public void testIndexHtml() throws IOException {
        try (InputStream in = url.openStream()) {
            String contents = new String(in.readAllBytes(), StandardCharsets.UTF_8);
            Assertions.assertTrue(contents.contains("<title>Testing Guide</title>"));
        }
    }
}
1 このアノテーションを使用すると、QuarkusインスタンスのURLを直接注入することができます。アノテーションの値は、URLのパス部分になります。

今のところ @TestHTTPResource では、URL の URI , URL , String 表現を注入することができます。

5. 特定のエンドポイントのテスト

RESTassured と @TestHTTPResource の両方で、パスをハードコーディングするのではなく、テストするエンドポイントクラスを指定することができます。これは現在、JAX-RS エンドポイント、サーブレット、リアクティブルートの両方をサポートしています。これにより、特定のテストがどのエンドポイントをテストしているかを正確に確認することが非常に簡単になりました。

これらの例では、以下のようなエンドポイントを想定しています:

@Path("/hello")
public class GreetingResource {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello";
    }
}
これは現在、JAX-RS のコンテキストパスを設定するための @ApplicationPath() アノテーションをサポートしていません。カスタムのコンテキストパスを設定したい場合は、代わりに quarkus.resteasy.path の設定値を使用してください。

5.1. テストHTTPリソース

io.quarkus.test.common.http.TestHTTPEndpoint アノテーションを使用してエンドポイントのパスを指定することが出来、指定されたエンドポイントからパスが抽出されます。 TestHTTPResource エンドポイントにも値を指定すると、エンドポイントパスの最後に追加されます。

package org.acme.getting.started.testing;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import io.quarkus.test.common.http.TestHTTPEndpoint;
import io.quarkus.test.common.http.TestHTTPResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class StaticContentTest {

    @TestHTTPEndpoint(GreetingResource.class)  (1)
    @TestHTTPResource
    URL url;

    @Test
    public void testIndexHtml() throws IOException {
        try (InputStream in = url.openStream()) {
            String contents = new String(in.readAllBytes(), StandardCharsets.UTF_8);
            Assertions.assertEquals("hello", contents);
        }
    }
}
1 GreetingResource@Path("/hello") とアノテーションされているので、注入された URL は /hello で終わります。

5.2. RESTassured

RESTassured ベースパス (すなわち、すべてのリクエストのルートとなるデフォルトパス) を制御するには、 io.quarkus.test.common.http.TestHTTPEndpoint アノテーションを使用できます。これはクラスやメソッドレベルで適用できます。グリーティングリソースをテストするには、以下のようにします:

package org.acme.getting.started.testing;

import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.common.http.TestHTTPEndpoint;
import org.junit.jupiter.api.Test;

import java.util.UUID;

import static io.restassured.RestAssured.when;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
@TestHTTPEndpoint(GreetingResource.class) (1)
public class GreetingResourceTest {

    @Test
    public void testHelloEndpoint() {
        when().get()    (2)
          .then()
             .statusCode(200)
             .body(is("hello"));
    }
}
1 これにより、RESTAssured はすべてのリクエストの前に /hello を付けます。
2 このテストでは /hello がデフォルトなので、ここでパスを指定する必要はないことに注意してください。

6. テストへの注入

これまでは、HTTP エンドポイントを介してアプリをテストする統合スタイルのテストしか取り上げてきませんでしたが、ユニットテストを行い、Beanを直接テストしたい場合はどうでしょうか?

Quarkusでは、 @Inject アノテーションを介してテストにCDI Beanを注入できるようにすることで、これをサポートしています(実際、Quarkusのテストは完全なCDI Beanなので、すべてのCDI機能を使用することができます)。HTTPを使用せずにグリーティングサービスを直接テストするシンプルなテストを作成してみましょう。

package org.acme.getting.started.testing;

import javax.inject.Inject;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class GreetingServiceTest {

    @Inject (1)
    GreetingService service;

    @Test
    public void testGreetingService() {
        Assertions.assertEquals("hello Quarkus", service.greeting("Quarkus"));
    }
}
1 GreetingService Beanがテストに注入されます。

7. テストへのインターセプターの適用

前述したように、Quarkusのテストは実際には完全なCDI Beanであり、通常のようにCDIインターセプターを適用することができます。例えば、トランザクションのコンテキスト内でテストメソッドを実行したい場合、 @Transactional アノテーションをメソッドに適用するだけで、トランザクションインターセプターがそれを処理します。

これに加えて、独自のテストステレオタイプを作成することもできます。例えば、以下のように @TransactionalQuarkusTest を作成することができます。

@QuarkusTest
@Stereotype
@Transactional
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TransactionalQuarkusTest {
}

このアノテーションをテストクラスに適用すると、 @QuarkusTest@Transactional の両方のアノテーションを適用したかのように動作します。

@TransactionalQuarkusTest
public class TestStereotypeTestCase {

    @Inject
    UserTransaction userTransaction;

    @Test
    public void testUserTransaction() throws Exception {
        Assertions.assertEquals(Status.STATUS_ACTIVE, userTransaction.getStatus());
    }

}

8. テストとトランザクション

テストでは標準のQuarkus @Transactional アノテーションを使用することができますが、これは、テストでデータベースに加えた変更が永続化されることを意味します。テストの終了時に変更をロールバックしたい場合は、 io.quarkus.test.TestTransaction アノテーションを使用することができます。これは、トランザクション内でテストメソッドを実行しますが、テストメソッドが完了したらロールバックして、データベースの変更を元に戻します。

9. QuarkusTest* コールバックによる強化

インターセプターの代わりに、あるいはインターセプターに加えて、以下のコールバックインターフェースを実装することで、 すべての @QuarkusTest クラスを充実させることができます。

  • io.quarkus.test.junit.callback.QuarkusTestBeforeClassCallback

  • io.quarkus.test.junit.callback.QuarkusTestAfterConstructCallback

  • io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback

  • io.quarkus.test.junit.callback.QuarkusTestBeforeTestExecutionCallback

  • io.quarkus.test.junit.callback.QuarkusTestAfterTestExecutionCallback

  • io.quarkus.test.junit.callback.QuarkusTestAfterEachCallback

オプションとして、プロパティ quarkus.test.enable-callbacks-for-integration-teststrue とすることで、これらのコールバックを @QuarkusIntegrationTest テストでも有効にすることができます。

このようなコールバックの実装は、 java.util.ServiceLoader で定義されている「サービスプロバイダ」として登録する必要があります。

例えば、以下のようなサンプルコールバックです:

package org.acme.getting.started.testing;

import io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback;
import io.quarkus.test.junit.callback.QuarkusTestMethodContext;

public class MyQuarkusTestBeforeEachCallback implements QuarkusTestBeforeEachCallback {

    @Override
    public void beforeEach(QuarkusTestMethodContext context) {
        System.out.println("Executing " + context.getTestMethod());
    }
}

次のように、src/main/resources/META-INF/services/io.quarkus.test.junit.callback.QuarkusTestBeforeEachCallback を介して登録する必要があります。

org.acme.getting.started.testing.MyQuarkusTestBeforeEachCallback
テストクラスやメソッドからアノテーションを読み込んで、コールバックが何をするかを制御することができます。
BeforeEachCallback のような JUnit Jupiter コールバックインターフェイスを使うことも可能ですが、QuarkusはJUnitが把握しないカスタムクラスローダーでテストを実行する必要がある為、クラスローディングの問題にぶつかるかもしれません。

10. 異なるプロファイルのテスト

これまでの例では、すべてのテストで Quarkus を 1 回だけ起動しました。最初のテストが実行される前に Quarkus が起動し、その後すべてのテストが実行され、最後に Quarkus がシャットダウンされます。これにより、非常に高速なテストが可能になりますが、様々な設定をテストすることができないため、少し制限されます。

この問題を回避するために、Quarkusはテストプロファイルの考え方をサポートしています。以前に実行したテストとは異なるプロファイルを持つテストがある場合、Quarkusはテストを実行する前にシャットダウンされ、新しいプロファイルで開始されます。これは、テスト時間にシャットダウン/起動サイクルが追加されるため、明らかに少し遅くなりますが、非常に大きな柔軟性が得られます。

Quarkus の再起動回数を減らすために、JUnit 5 User Guide にあるように io.quarkus.test.junit.util.QuarkusTestProfileAwareClassOrderer がグローバルな ClassOrderer として登録されています。この ClassOrderer の動作は junit-platform.properties で設定することができます (詳細はソースコードや javadoc を参照してください)。また、JUnit 5 が提供する別の ClassOrderer を設定することで、完全に無効にすることも可能です (独自のものを設定することも可能です)。さらに JUnit 5.8.2 の時点は、単一の junit-platform.properties のみがピックアップされ、複数見つかった場合は警告が記録されることに注意してください。 このような警告が発生した場合は、Quarkus が提供する junit-platform.properties をクラスパスから除外することで、警告を取り除くことができます。

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5-properties</artifactId>
        </exclusion>
    </exclusions>
</dependency>

10.1. プロフィールの書き方

テストプロファイルを実装するには、 io.quarkus.test.junit.QuarkusTestProfile .

package org.acme.getting.started.testing;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.QuarkusTestProfile.TestResourceEntry;

public class MockGreetingProfile implements QuarkusTestProfile { (1)

    /**
     * Returns additional config to be applied to the test. This
     * will override any existing config (including in application.properties),
     * however existing config will be merged with this (i.e. application.properties
     * config will still take effect, unless a specific config key has been overridden).
     *
     * Here we are changing the JAX-RS root path.
     */
    @Override
    public Map<String, String> getConfigOverrides() {
        return Collections.singletonMap("quarkus.resteasy.path","/api");
    }

    /**
     * Returns enabled alternatives.
     *
     * This has the same effect as setting the 'quarkus.arc.selected-alternatives' config key,
     * however it may be more convenient.
     */
    @Override
    public Set<Class<?>> getEnabledAlternatives() {
        return Collections.singleton(MockGreetingService.class);
    }

    /**
     * Allows the default config profile to be overridden. This basically just sets the quarkus.test.profile system
     * property before the test is run.
     *
     * Here we are setting the profile to test-mocked
     */
    @Override
    public String getConfigProfile() {
        return "test-mocked";
    }

    /**
     * Additional {@link QuarkusTestResourceLifecycleManager} classes (along with their init params) to be used from this
     * specific test profile.
     *
     * If this method is not overridden, then only the {@link QuarkusTestResourceLifecycleManager} classes enabled via the {@link io.quarkus.test.common.QuarkusTestResource} class
     * annotation will be used for the tests using this profile (which is the same behavior as tests that don't use a profile at all).
     */
    @Override
    public List<TestResourceEntry> testResources() {
        return Collections.singletonList(new TestResourceEntry(CustomWireMockServerManager.class));
    }


    /**
     * If this returns true then only the test resources returned from {@link #testResources()} will be started,
     * global annotated test resources will be ignored.
     */
    @Override
    public boolean disableGlobalTestResources() {
        return false;
    }

    /**
     * The tags this profile is associated with.
     * When the {@code quarkus.test.profile.tags} System property is set (its value is a comma separated list of strings)
     * then Quarkus will only execute tests that are annotated with a {@code @TestProfile} that has at least one of the
     * supplied (via the aforementioned system property) tags.
     */
    @Override
    public Set<String> tags() {
        return Collections.emptySet();
    }

    /**
     * The command line parameters that are passed to the main method on startup.
     */
    @Override
    public String[] commandLineParameters() {
        return new String[0];
    }

    /**
     * If the main method should be run.
     */
    @Override
    public boolean runMainMethod() {
        return false;
    }

    /**
     * If this method returns true then all {@code StartupEvent} and {@code ShutdownEvent} observers declared on application
     * beans should be disabled.
     */
    @Override
    public boolean disableApplicationLifecycleObservers() {
        return false;
    }
}
1 これらのメソッドにはすべてデフォルトの実装があるため、オーバーライドが必要なメソッドのみオーバーライドします。

これでプロファイルを定義したので、それをテストクラスに含める必要があります。そのためには、テストクラスに @TestProfile(MockGreetingProfile.class) アノテーションを付けます。

テストプロファイルの設定はすべて単一のクラスに保存されているので、前回のテストが同じ設定で実行されたかどうかが簡単にわかります。

10.2. 特定のテストの実行

Quarkus は、テストの実行を特定の @TestProfile アノテーションを持つテストに制限できます。これは、QuarkusTestProfiletags メソッドを quarkus.test.profile.tags システムプロパティーと組み合わせて利用することで機能します。

基本的に、quarkus.test.profile.tags の値と一致するタグが少なくとも 1 つある QuarkusTestProfile はアクティブであると見なされ、アクティブなプロファイルの @TestProfile でアノテーションが付けられたすべてのテストが実行されますが、それ以外はスキップされます。以下は、その典型的な例です。

まず、次のようないくつかの QuarkusTestProfile 実装を定義しましょう。

public class Profiles {

    public static class NoTags implements QuarkusTestProfile {

    }

    public static class SingleTag implements QuarkusTestProfile {
        @Override
        public Set<String> tags() {
            return Collections.singleton("test1");
        }
    }

    public static class MultipleTags implements QuarkusTestProfile {
        @Override
        public Set<String> tags() {
            return new HashSet<>(Arrays.asList("test1", "test2"));
        }
    }
}

ここで、次のテストがあると仮定します。

@QuarkusTest
public class NoQuarkusProfileTest {

    @Test
    public void test() {
        // test something
    }
}
@QuarkusTest
@TestProfile(Profiles.NoTags.class)
public class NoTagsTest {

    @Test
    public void test() {
        // test something
    }
}
@QuarkusTest
@TestProfile(Profiles.SingleTag.class)
public class SingleTagTest {

    @Test
    public void test() {
        // test something
    }
}
@QuarkusTest
@TestProfile(Profiles.MultipleTags.class)
public class MultipleTagsTest {

    @Test
    public void test() {
        // test something
    }
}

次のシナリオを考えてみましょう。

  • quarkus.test.profile.tags が設定されていない: すべてのテストが実行されます。

  • quarkus.test.profile.tags=foo: この場合、QuarkusTestProfile 実装で定義されたタグはいずれも quarkus.test.profile.tags の値と一致しないため、テストは実行されません。@TestProfile でアノテーションが付けられていないため、NoQuarkusProfileTest も実行されないことに注意してください。

  • quarkus.test.profile.tags=test1: この場合、それぞれの QuarkusTestProfile 実装のタグが quarkus.test.profile.tags の値と一致するため、SingleTagTestMultipleTagsTest が実行されます。

  • quarkus.test.profile.tags=test1,test3: この場合、前の場合と同じテストが実行されます。

  • quarkus.test.profile.tags=test2,test3: この場合、MultipleTagsTest は、tags メソッドが quarkus.test.profile.tags の値と一致する唯一の QuarkusTestProfile 実装であるため、MultipleTagsTest のみ実行されます。

11. モックサポート

Quarkusでは、2つの異なるアプローチを使用したモックオブジェクトの使用をサポートしています。CDIの代替品を使用してすべてのテストクラスのBeanをモックアウトするか、 QuarkusMock を使用してテストごとにBeanをモックアウトすることができます。

11.1. CDI @Alternative メカニズム

これを使用するには、 src/test/java ディレクトリーのクラスでモックしたいBeanをオーバーライドし、 @Alternative@Priority(1) アノテーションをBeanに配置するだけです。あるいは、便利な io.quarkus.test.Mock ステレオタイプアノテーションを使用することもできます。この組み込みステレオタイプは、 @Alternative@Priority(1)@Dependent を宣言します。例えば、以下のようなサービスがあるとします:

@ApplicationScoped
public class ExternalService {

    public String service() {
        return "external";
    }

}

src/test/java で以下のクラスでモックできました:

@Mock
@ApplicationScoped (1)
public class MockExternalService extends ExternalService {

    @Override
    public String service() {
        return "mock";
    }
}
1 @Mock ステレオタイプで宣言された @Dependent スコープをオーバーライドします。

代替品が src/main/java ではなく src/test/java ディレクトリーに存在することが重要です。そうでなければ、テスト以外も常に有効になってしまいます。

現時点では、このアプローチはネイティブイメージテストでは機能しないことに注意してください。これには、代替テストをネイティブイメージに焼き付ける必要があるためです。

11.2. QuarkusMock を使用したモッキング

io.quarkus.test.junit.QuarkusMock クラスは、通常のスコープ付きBeanを一時的にモックアウトするために使用することができます。 @BeforeAll メソッドでこのメソッドを使用した場合、モックは現在のクラスのすべてのテストに対して有効になりますが、test メソッドでこれを使用した場合、モックは現在のテストの間のみ有効になります。

この方法は、通常のスコープ付き CDI Bean(例: @ApplicationScoped , @RequestScoped など、 @Singleton@Dependent 以外の基本的にすべてのスコープ)に対して使用することができます。

使用例は次のようになります:

@QuarkusTest
public class MockTestCase {

    @Inject
    MockableBean1 mockableBean1;

    @Inject
    MockableBean2 mockableBean2;

    @BeforeAll
    public static void setup() {
        MockableBean1 mock = Mockito.mock(MockableBean1.class);
        Mockito.when(mock.greet("Stuart")).thenReturn("A mock for Stuart");
        QuarkusMock.installMockForType(mock, MockableBean1.class);  (1)
    }

    @Test
    public void testBeforeAll() {
        Assertions.assertEquals("A mock for Stuart", mockableBean1.greet("Stuart"));
        Assertions.assertEquals("Hello Stuart", mockableBean2.greet("Stuart"));
    }

    @Test
    public void testPerTestMock() {
        QuarkusMock.installMockForInstance(new BonjourGreeter(), mockableBean2); (2)
        Assertions.assertEquals("A mock for Stuart", mockableBean1.greet("Stuart"));
        Assertions.assertEquals("Bonjour Stuart", mockableBean2.greet("Stuart"));
    }

    @ApplicationScoped
    public static class MockableBean1 {

        public String greet(String name) {
            return "Hello " + name;
        }
    }

    @ApplicationScoped
    public static class MockableBean2 {

        public String greet(String name) {
            return "Hello " + name;
        }
    }

    public static class BonjourGreeter extends MockableBean2 {
        @Override
        public String greet(String name) {
            return "Bonjour " + name;
        }
    }
}
1 インジェクションされたインスタンスはここでは利用できないので、 installMockForType を使用します。このモックは両方のテストメソッドに使用されます。
2 私たちは installMockForInstance を使用して注入されたBeanを置き換えます。

Mockitoには依存しないことに注意してください。好きなモッキングライブラリを使うことができますし、必要な動作を提供するためにオブジェクトを手動でオーバーライドすることもできます。

@Inject を使用すると、インストールしたモックインスタンスへの CDI プロキシーを取得できます。これは、モックインスタンス自体が必要な Mockito.verify などのメソッドに渡すのには適していません。したがって、verify などのメソッドを呼び出す必要がある場合は、テストでモックインスタンスを保持するか、以下のように @InjectMock を使用する必要があります。

11.2.1. @InjectMock での更なる単純化

QuarkusMock で提供されている機能をベースに、Quarkusでは、 QuarkusMock でサポートされているBeanをモックするために Mockito を簡単に利用できるようにしています。この機能は、 quarkus-junit5-mockito 依存関係で利用可能な @io.quarkus.test.junit.mockito.InjectMock アノテーションを介して利用できます。

@InjectMock を使用すると、先ほどの例は次のように書くことができます:

@QuarkusTest
public class MockTestCase {

    @InjectMock
    MockableBean1 mockableBean1; (1)

    @InjectMock
    MockableBean2 mockableBean2;

    @BeforeEach
    public void setup() {
        Mockito.when(mockableBean1.greet("Stuart")).thenReturn("A mock for Stuart"); (2)
    }

    @Test
    public void firstTest() {
        Assertions.assertEquals("A mock for Stuart", mockableBean1.greet("Stuart"));
        Assertions.assertEquals(null, mockableBean2.greet("Stuart")); (3)
    }

    @Test
    public void secondTest() {
        Mockito.when(mockableBean2.greet("Stuart")).thenReturn("Bonjour Stuart"); (4)
        Assertions.assertEquals("A mock for Stuart", mockableBean1.greet("Stuart"));
        Assertions.assertEquals("Bonjour Stuart", mockableBean2.greet("Stuart"));
    }

    @ApplicationScoped
    public static class MockableBean1 {

        public String greet(String name) {
            return "Hello " + name;
        }
    }

    @ApplicationScoped
    public static class MockableBean2 {

        public String greet(String name) {
            return "Hello " + name;
        }
    }
}
1 @InjectMock により、モックがテストクラスのテストメソッドに存在することになり、利用可能になります (他のテストクラスはこの影響を受け ません )。
2 クラスのすべてのテストメソッドに対して mockableBean1 が設定されています。
3 mockableBean2 のモックが設定されていないので、デフォルトの Mockito レスポンスを返します。
4 このテストでは、 mockableBean2 が設定されているので、設定されたレスポンスを返します。

上のテストは @InjectMock の機能を示すのには良いですが、実際のテストを上手く表してはいません。実際のテストでは、ほとんどの場合、モックを設定し、モックされたBeanを使用するBeanをテストします。以下に例を示します:

@QuarkusTest
public class MockGreetingServiceTest {

    @InjectMock
    GreetingService greetingService;

    @Test
    public void testGreeting() {
        when(greetingService.greet()).thenReturn("hi");
        given()
                .when().get("/greeting")
                .then()
                .statusCode(200)
                .body(is("hi")); (1)
    }

    @Path("greeting")
    public static class GreetingResource {

        final GreetingService greetingService;

        public GreetingResource(GreetingService greetingService) {
            this.greetingService = greetingService;
        }

        @GET
        @Produces("text/plain")
        public String greet() {
            return greetingService.greet();
        }
    }

    @ApplicationScoped
    public static class GreetingService {
        public String greet(){
            return "hello";
        }
    }
}
1 greetingService をモックとして設定したので、 GreetingService Beanを使用する GreetingResource は、通常の GreetingService Beanのレスポンスの代わりにモックされたレスポンスを取得します。

デフォルトでは、@InjectMock アノテーションは、通常の CDI スコープ Bean (@ApplicationScoped@RequestScoped など) に使用できます。@Singleton Bean のモックは、convertScopes プロパティーを true に設定することで実行できます (@InjectMock (convertScopes = true など)。これにより、@Singleton Bean がテスト用の @ApplicationScoped Bean に変換されます。.

これは高度なオプションと見なされ、Bean のスコープを変更することで引き起こされる結果を完全に理解している場合にのみ実行する必要があります。

11.2.2. @InjectSpy で、モックの代わりにスパイを使用する

InjectMock で提供されている機能をベースに、 QuarkusMock でサポートされているBeanをスパイするために Mockito を簡単に利用できるようにしました。この機能は、 quarkus-junit5-mockito 依存関係で利用可能な @io.quarkus.test.junit.mockito.InjectSpy アノテーションを介して利用できます。

テストを行う際に、特定の論理パスが取られたかどうかを確認するだけで済む場合もありますし、Spied クローン上で残りのメソッドを実行している間に、1つのメソッドのレスポンスをスタブアウトするだけで済む場合もあります。Spy パーシャル モックの詳細については Mockito のドキュメントを参照してください。いずれの場合も、オブジェクトの Spy が望ましいでしょう。 @InjectSpy を使用して、先ほどの例は次のように書くことができます。

@QuarkusTest
public class SpyGreetingServiceTest {

    @InjectSpy
    GreetingService greetingService;

    @Test
    public void testDefaultGreeting() {
        given()
                .when().get("/greeting")
                .then()
                .statusCode(200)
                .body(is("hello"));

        Mockito.verify(greetingService, Mockito.times(1)).greet(); (1)
    }

    @Test
    public void testOverrideGreeting() {
        when(greetingService.greet()).thenReturn("hi"); (2)
        given()
                .when().get("/greeting")
                .then()
                .statusCode(200)
                .body(is("hi")); (3)
    }

    @Path("greeting")
    public static class GreetingResource {

        final GreetingService greetingService;

        public GreetingResource(GreetingService greetingService) {
            this.greetingService = greetingService;
        }

        @GET
        @Produces("text/plain")
        public String greet() {
            return greetingService.greet();
        }
    }

    @ApplicationScoped
    public static class GreetingService {
        public String greet(){
            return "hello";
        }
    }
}
1 値をオーバーライドするのではなく、 GreetingService の greet メソッドがこのテストで呼び出されたことを確認したいだけです。
2 ここでは、"hello"の代わりに"hi"を返すようにSpyに指示しています。 GreetingResourceGreetingService から挨拶を要求するとき、通常の GreetingService Bean のレスポンスの代わりにモックされたレスポンスを取得します。
3 私たちは、スパイからのモックされた応答を得ることを検証しています。

11.2.3. @InjectMock との併用 @RestClient

@RegisterRestClient は、実行時に rest-client の実装を登録しています。Beanは通常のスコープである必要があるため、インターフェイスに @ApplicationScoped を付与する必要があります。

@Path("/")
@ApplicationScoped
@RegisterRestClient
public interface GreetingService {

    @GET
    @Path("/hello")
    @Produces(MediaType.TEXT_PLAIN)
    String hello();
}

テストクラスの例です:

@QuarkusTest
public class GreetingResourceTest {

    @InjectMock
    @RestClient (1)
    GreetingService greetingService;

    @Test
    public void testHelloEndpoint() {
        Mockito.when(greetingService.hello()).thenReturn("hello from mockito");

        given()
          .when().get("/hello")
          .then()
             .statusCode(200)
             .body(is("hello from mockito"));
    }

}
1 この注入ポイントが RestClient のインスタンスを使用することを意味していることを示します。

11.3. Mocking with Panache

quarkus-hibernate-orm-panachequarkus-mongodb-panache のエクステンションを使っている場合は、Hibernate ORM と Panache モック および MongoDB と Panache モック のドキュメントをチェックして、データアクセスをモックする最も簡単な方法を確認してください。

12. セキュリティーのテスト

Quarkus Securityを使用している場合、アプリケーションのセキュリティー機能を簡単にテストする方法については、セキュリティーのテスト のセクションをご覧ください。

13. Quarkus アプリケーションの開始前にサービスを開始する

非常に一般的なニーズは、Quarkusアプリケーションがテストを開始する前に、Quarkusアプリケーションに依存するいくつかのサービスを開始することです。このニーズに対応するために、Quarkusでは、 @io.quarkus.test.common.QuarkusTestResourceio.quarkus.test.common.QuarkusTestResourceLifecycleManager を提供します。

テストスイート内のテストに @QuarkusTestResource のアノテーションを付けるだけで、Quarkus は、テストが実行される前に対応する QuarkusTestResourceLifecycleManager を実行します。テストスイートは、複数の @QuarkusTestResource アノテーションを自由に利用することもできます。この場合、対応するすべての QuarkusTestResourceLifecycleManager オブジェクトがテストの前に実行されます。複数のテストリソースを使用する場合、それらを同時に開始できます。そのためには、@QuarkusTestResource(parallel = true) を設定する必要があります。

テストリソースは、テストクラスまたはカスタムプロファイルで定義されている場合でもグローバルです。つまり、重複を削除しても、すべてのテストですべてアクティブになります。単一のテストクラスまたはテストプロファイルに限定してテストリソースを有効にする場合は、@QuarkusTestResource(restrictToAnnotatedClass = true) を使用できます。

Quarkusでは、QuarkusTestResourceLifecycleManager の実装がいくつか提供されていますが (H2 データベースを起動する io.quarkus.test.h2.H2DatabaseTestResource や、モック Kubernetes API サーバーを起動する io.quarkus.test.kubernetes.client.KubernetesServerTestResource を参照)、特定のアプリケーションのニーズに対応するためにカスタム実装を作成するのが一般的です。一般的なケースとしては、Testcontainers を使用した docker コンテナーの起動 (その例は こちら を参照)、Wiremock を使用したモック HTTP サーバの起動 (その例は こちら を参照) などがあります。

13.1. テストクラスの変更

テストクラスに何かを注入する必要があるカスタム の QuarkusTestResourceLifecycleManager を作成する場合、inject メソッドを使用できます。たとえば、次のようなテストがある場合:

@QuarkusTest
@QuarkusTestResource(MyWireMockResource.class)
public class MyTest {

    @InjectWireMock // this a custom annotation you are defining in your own application
    WireMockServer wireMockServer;

    @Test
    public someTest() {
        // control wiremock in some way and perform test
    }
}

次のコードスニペットの inject メソッドに示すように、MyWireMockResourcewireMockServer フィールドを注入させることができます。

public class MyWireMockResource implements QuarkusTestResourceLifecycleManager {

    WireMockServer wireMockServer;

    @Override
    public Map<String, String> start() {
        wireMockServer = new WireMockServer(8090);
        wireMockServer.start();

        // create some stubs

        return Map.of("some.service.url", "localhost:" + wireMockServer.port());
    }

    @Override
    public synchronized void stop() {
        if (wireMockServer != null) {
            wireMockServer.stop();
            wireMockServer = null;
        }
    }

    @Override
    public void inject(TestInjector testInjector) {
        testInjector.injectIntoFields(wireMockServer, new TestInjector.AnnotatedAndMatchesType(InjectWireMock.class, WireMockServer.class));
    }
}
テストクラスへのこの注入は CDI の制御下になく、CDI がテストクラスへの必要な注入を実行した後に発生することは言及に値します。

13.2. アノテーションベースのテストリソース

アノテーションを使用して有効化および設定されたテストリソースを作成することができます。これは、テストリソースの有効化と設定に使用されるアノテーション に @QuarkusTestResource を配置することで可能になります。

たとえば、これは @WithKubernetesTestServer アノテーションを定義します。これは、テストで KubernetesServerTestResource をアクティブ化するために使用できますが、アノテーションが付けられたテストクラスに限定されます。これは QuarkusTestProfile テストプロファイルに配置することもできます。

@QuarkusTestResource(KubernetesServerTestResource.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface WithKubernetesTestServer {
    /**
     * Start it with HTTPS
     */
    boolean https() default false;

    /**
     * Start it in CRUD mode
     */
    boolean crud() default true;

    /**
     * Port to use, defaults to any available port
     */
    int port() default 0;
}

KubernetesServerTestResource クラスは、前のアノテーションを使用して設定するために、QuarkusTestResourceConfigurableLifecycleManager インターフェイスを実装する必要があります。

public class KubernetesServerTestResource
        implements QuarkusTestResourceConfigurableLifecycleManager<WithKubernetesTestServer> {

    private boolean https = false;
    private boolean crud = true;
    private int port = 0;

    @Override
    public void init(WithKubernetesTestServer annotation) {
        this.https = annotation.https();
        this.crud = annotation.crud();
        this.port = annotation.port();
    }

    // ...
}

14. ハング検出

@QuarkusTest は、予期しないハングを診断するために使用できるハング検出をサポートしています。指定された時間内に進捗がない場合 (つまり、JUnit コールバックが呼び出されない場合)、Quarkus はスタックトレースをコンソールに出力して、ハングの診断を助けます。このタイムアウトのデフォルト値は 10 分です。

これ以上のアクションは実行されず、テストは通常どおり (通常は CI がタイムアウトするまで) 続行されますが、出力されたスタックトレースは、ビルドが失敗した理由を診断するのに役立ちます。このタイムアウトは、quarkus.test.hang-detection-timeout システムプロパティーで制御できます (これは application.properties でも設定できますが、Quarkus が起動するまで読み取られないため、Quarkus の起動タイムアウトはデフォルトの 10 分です)。

15. ネイティブ実行可能ファイルテスト

@QuarkusIntegrationTest を使用してネイティブ実行可能ファイルをテストすることも可能です。これは、テストに注入すること (そして、ネイティブ実行可能ファイルは別の非 JVM プロセスで実行されることーこれは実際には可能ではありません) を除いて、このガイドで述べたすべての機能をサポートしています。

これについては、ネイティブ実行可能ファイルガイド で説明されています。

16. @QuarkusIntegrationTest の使用

@QuarkusIntegrationTest は、Quarkus ビルドによって生成されたアーティファクトを起動およびテストするために使用する必要があり、jar (タイプを問わず)、ネイティブイメージ、またはコンテナーイメージのテストをサポートします。簡単に言えば、Quarkus ビルド (mvn package または gradle build) の結果が jar である場合、その jar は java -jar …​ として起動され、それに対してテストが実行されることを意味します。ネイティブイメージがビルドされた場合、アプリケーションは ./application …​ として起動され、実行中のアプリケーションに対してテストが実行されます。最後に、ビルド中に ( quarkus-container-image-jib または quarkus-container-image-docker エクステンションを含め、 quarkus.container-image.build=true プロパティーを設定することで) コンテナーイメージが作成された場合)、コンテナーが作成されて実行されます (これには、docker 実行可能ファイルが存在する必要があります)。

@NativeImageTest の場合と同様に、これは同じセットの機能をサポートし、同じ制限があるブラックボックステストです。

@QuarkusIntegrationTest でアノテーションが付けられたテストはビルドの結果をテストするため、統合テストスイートの一部として実行する必要があります。 - 例えば、Maven を使用している場合は -DskipITs=false を設定し、Gradle を使用している場合は quarkusIntTest タスクを設定します。これらのテストは、Quarkus がまだ最終のアーティファクトを作成していないため、@QuarkusTest と同じフェーズで実行すると 機能しません

pom.xml ファイルには以下が含まれます。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>${surefire-plugin.version}</version>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
            <configuration>
                <systemPropertyVariables>
                    <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
                    <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                    <maven.home>${maven.home}</maven.home>
                </systemPropertyVariables>
            </configuration>
        </execution>
    </executions>
</plugin>

これは、failsafe-maven-plugin に統合テストを実行するように指示します。

次に、src/test/java/org/acme/quickstart/GreetingResourceIT.java を開きます。次の内容が含まれています:

package org.acme.quickstart;


import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest (1)
public class GreetingResourceIT extends GreetingResourceTest { (2)

    // Run the same tests

}
1 テストの前にネイティブファイルからアプリケーションを起動する別のテストランナーを使用します。実行可能ファイルは、Failsafe Maven Plugin によって取得されます。
2 便宜上、以前のテストを拡張していますが、独自のテストを実装することもできます。

詳細については、次のリンクを参照してください: building-native-image#testing-the-native-executable[ネイティブ実行可能ファイルのテストのガイド]

16.1. コンテナーの起動

@QuarkusIntegrationTest によってコンテナーが起動されると (アプリケーションは quarkus.container-image.buildtrue に設定されているため)、コンテナーは予測可能なコンテナーネットワーク上で起動されます。これにより、アプリケーションをサポートするためにサービスを起動する必要がある統合テストの作成が容易になります。これは、@QuarkusIntegrationTest が、Dev Services を介して起動されたコンテナーでそのまま機能することを意味しますが、追加のコンテナーを起動する QuarkusTestLifecycleManager リソースを使用して有効化することも意味します。これは、QuarkusTestLifecycleManagerio.quarkus.test.common.DevServicesContext.ContextAware を実装することで実現できます。以下は、その簡単な例です。

テストするリソースを実行しているコンテナー (たとえば Testcontainers を介した PostgreSQL) には、コンテナーのネットワークから IP アドレスが割り当てられます。コンテナーのネットワークからの「パブリック」IP と「マップされていない」ポート番号を使用してサービスに接続します。Testcontainers ライブラリーは通常、コンテナーネットワークを尊重せずに接続文字列を返すため、コンテナーネットワーク上のコンテナーの IP と_マップされていない_ポート番号を使用して Quarkus に正しい接続文字列を提供するには、追加のコードが必要です。

次の例は PostgreSQL での使用法を示していますが、このアプローチはすべてのコンテナーに適用できます。

import io.quarkus.test.common.DevServicesContext;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

import org.testcontainers.containers.JdbcDatabaseContainer;
import org.testcontainers.containers.PostgreSQLContainer;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class CustomResource implements QuarkusTestResourceLifecycleManager, DevServicesContext.ContextAware {

    private Optional<String> containerNetworkId;
    private JdbcDatabaseContainer container;

    @Override
    public void setIntegrationTestContext(DevServicesContext context) {
        containerNetworkId = context.containerNetworkId();
    }

    @Override
    public Map<String, String> start() {
        // start a container making sure to call withNetworkMode() with the value of containerNetworkId if present
        container = new PostgreSQLContainer<>("postgres:latest").withLogConsumer(outputFrame -> {});

        // apply the network to the container
        containerNetworkId.ifPresent(container::withNetworkMode);

        // start container before retrieving its URL or other properties
        container.start();

        String jdbcUrl = container.getJdbcUrl();
        if (containerNetworkId.isPresent()) {
            // Replace hostname + port in the provided JDBC URL with the hostname of the Docker container
            // running PostgreSQL and the listening port.
            jdbcUrl = fixJdbcUrl(jdbcUrl);
        }

        // return a map containing the configuration the application needs to use the service
        return ImmutableMap.of(
            "quarkus.datasource.username", container.getUsername(),
            "quarkus.datasource.password", container.getPassword(),
            "quarkus.datasource.jdbc.url", jdbcUrl);
    }

    private String fixJdbcUrl(String jdbcUrl) {
        // Part of the JDBC URL to replace
        String hostPort = container.getHost() + ':' + container.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT);

        // Host/IP on the container network plus the unmapped port
        String networkHostPort =
            container.getCurrentContainerInfo().getConfig().getHostName()
            + ':'
            + PostgreSQLContainer.POSTGRESQL_PORT;

        return jdbcUrl.replace(hostPort, networkHostPort);
    }

    @Override
    public void stop() {
        // close container
    }
}

このドキュメントの対応するセクションで説明されているように、CustomResource@QuarkusTestResource を使用して @QuarkusIntegrationTest でアクティブ化されます。

16.2. 実行中のアプリケーションに対するテストの実行

この機能は実験的なものと見なされており、Quarkus の将来のバージョンで変更される可能性があります。

@QuarkusIntegrationTest は、アプリケーションのすでに実行中のインスタンスに対するテストの実行をサポートします。これは、テストの実行時に quarkus.http.test-host システムプロパティーを設定することで実現できます。

次の Maven コマンドはその使用例で、@ QuarkusIntegrationTest を強制的に実行し、http://1.2.3.4:4321 からアクセスできます。

./mvnw verify -Dquarkus.http.test-host=1.2.3.4 -Dquarkus.http.test-port=4321

17. @QuarkusTest と他のタイプのテストを混合

@QuarkusTest でアノテーションが付けられたテストと、@QuarkusDevModeTest@QuarkusProdModeTest@QuarkusUnitTest のいずれかでアノテーションが付けられたテストを、1 回の実行 (たとえば、1 回の Maven Surefire プラグインの実行) で混合することはできません。ただsじょ。後者の 3 つは共存できます。

この制限の理由は、@QuarkusTest がテスト実行の期間全体にわたって Quarkus サーバーを起動するため、他のテストが独自の Quarkus サーバーを起動できないようにするためです。

この制限を緩和するために、@QuarkusTest アノテーションは JUnit5 @Tag を定義します: io.quarkus.test.junit.QuarkusTest 。このタグを使用して、特定の実行 で @QuarkusTest テストを分離できます。以下は Maven Surefire プラグインを使用した例です。

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire-plugin.version}</version>
    <executions>
        <execution>
            <id>default-test</id>
            <goals>
                <goal>test</goal>
            </goals>
            <configuration>
                <excludedGroups>io.quarkus.test.junit.QuarkusTest</excludedGroups>
            </configuration>
        </execution>
        <execution>
            <id>quarkus-test</id>
            <goals>
                <goal>test</goal>
            </goals>
            <configuration>
                <groups>io.quarkus.test.junit.QuarkusTest</groups>
            </configuration>
        </execution>
    </executions>
    <configuration>
        <systemProperties>
            <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
        </systemProperties>
    </configuration>
</plugin>

18. IDE から @QuarkusTest を実行する

ほとんどの IDE では、選択したクラスを JUnit テストとして直接実行できるようになっています。そのためには、選択した IDE の設定でいくつかのプロパティーを設定する必要があります。

  • java.util.logging.manager (ロギングガイド を参照)

  • maven.home (${maven.home}/conf/settings.xml にカスタム設定がある場合のみ)、Maven Guide を参照)

  • maven.settings (カスタム版の settings.xml ファイルをテストに使用する場合)

18.1. Eclipse の別個の JRE 定義

現在の"Installed JRE"定義を新しい定義にコピーし、新しいVMの引数としてプロパティーを追加します:

  • -Djava.util.logging.manager=org.jboss.logmanager.LogManager

  • -Dmaven.home=<path-to-your-maven-installation>

このJRE定義をQuarkusプロジェクトのターゲットランタイムとして使用すると、「Run as JUnit」設定に回避策が適用されます。

18.2. VSCode "run with" 設定

プロジェクトディレクトリーやワークスペースのルートにある settings.json には、テスト設定で次の回避策が必要です。

"java.test.config": [
    {
        "name": "quarkusConfiguration",
        "vmargs": [ "-Djava.util.logging.manager=org.jboss.logmanager.LogManager -Dmaven.home=<path-to-your-maven-installation> ..." ],
        ...
    },
  ...
]

18.3. IntelliJ IDEA JUnit テンプレート

IntelliJ IDEA では何も必要ありません。なぜなら、IDEは systemPropertyVariables を `pom.xml`の surefire プラグイン設定から取得するからです。

19. 開発サービスのテスト

デフォルトでは、テストは Dev Services でのみ機能するはずですが、一部のユースケースでは、テストで自動的に設定されたプロパティーにアクセスする必要がある場合があります。

これは、@QuarkusTest または @QuarkusIntegrationTest に直接注入できる io.quarkus.test.common.DevServicesContext を使用して行うことができます。タイプ DevServicesContext のフィールドを定義するだけで、自動的に注入されます。これを使用して、設定されている任意のプロパティーを取得できます。通常、これは、テスト自体からリソースに直接接続するために使用されます。たとえば、kafka に接続して、テスト対象のアプリケーションにメッセージを送信するために使用されます。

io.quarkus.test.common.DevServicesContext.ContextAware を実装するオブジェクトへの注入もサポートされています。io.quarkus.test.common.DevServicesContext.ContextAware を実装するフィールドがある場合、Quarkus は` setIntegrationTestContext` メソッドを呼び出して、コンテキストをこのオブジェクトに渡します。これにより、クライアントロジックをユーティリティークラスにカプセル化できます。

QuarkusTestResourceLifecycleManager 実装は、ContextAware を実装してこれらのプロパティーにアクセスすることもできます。これにより、Quarkus が起動する前にリソースを設定できます (たとえば、KeyCloak インスタンスの設定、データベースへのデータの追加など)。

アプリケーションをコンテナーとしてランチャーにする @QuarkusIntegrationTest テストの場合、io.quarkus.test.common.DevServicesContext は、アプリケーションコンテナーが起動されたコンテナーネットワークの ID へのアクセスも提供します (containerNetworkId メソッドを使用)。これは、アプリケーションが通信する追加のコンテナーを起動する必要がある QuarkusTestResourceLifecycleManager で使用できます。