第4章 Camel Quarkus でのルートのテスト


4.1. Camel Quarkus エクステンションのテスト

テストは、Camel ルートが長期にわたって期待どおりに動作することを確認するための良い方法です。まだの場合は、「Camel Quarkus User guide」の First Steps セクションと Quarkus ドキュメントの Testing your application セクションをご一読ください。

Quarkus のコンテキストでルートをテストする場合、ローカル統合テストを作成することが推奨されます。これには、JVM モードとネイティブモードの両方をカバーできるという利点があります。

JVM モードでは、CamelTestSupport スタイルのテスト を使用できます。

4.1.1. JVM モードでの実行

JVM モードでは、@QuarkusTest アノテーションを使用して Quarkus をブートストラップし、@Test ロジックが実行される に Camel ルートを起動します。

以下に例を示します。

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

@QuarkusTest
class MyTest {
    @Test
    public void test() {
        // Use any suitable code that sends test data to the route and then assert outcomes
        ...
    }
}
Copy to Clipboard
ヒント

サンプル実装は Camel Quarkus ソースにあります。

4.1.2. ネイティブモードでの実行

注記

サポートされているすべてのエクステンションに対して、アプリケーションがネイティブモードで動作することを常にテストしてください。

それぞれの JVM モードクラスからロジックを継承することにより、JVM モード用に定義されたテストロジックを再利用できます。

@QuarkusIntegrationTest アノテーションを追加して、Quarkus JUnit エクステンションに、テスト対象のアプリケーションをネイティブイメージにコンパイルし、テストを実行する前にイメージを起動するように指示します。

import io.quarkus.test.junit.QuarkusIntegrationTest;

@QuarkusIntegrationTest
class MyIT extends MyTest {
   ...
}
Copy to Clipboard
ヒント

サンプル実装は Camel Quarkus ソースにあります。

4.1.3. @QuarkusTest@QuarkusIntegrationTest の違い

ネイティブ実行可能ファイルは、バイトコードではなくネイティブコードであるため、実行に JVM を必要とせず、また JVM で実行することもできません。

従来の JVM を使用して実行するために、テストをネイティブコードにコンパイルしても意味はありません。

そのため、テストとアプリケーション間の通信は、ネットワーク (HTTP/REST、またはアプリケーションが使用するその他のプロトコル)、ファイルシステム (ログファイルなど) の監視、またはその他のプロセス間通信を介して行う必要があります。

4.1.3.1. JVM モードでの @QuarkusTest

JVM モードでは、@QuarkusTest のアノテーションが付けられたテストは、テスト対象のアプリケーションと同じ JVM で実行されます。

これは、@Inject を使用して、アプリケーションからテストコードに Bean を追加できることを意味します。

@jakarta.enterprise.inject.Alternative および @jakarta.annotation.Priority を使用して、新しい Bean を定義したり、アプリケーションから Bean をオーバーライドしたりすることもできます。

4.1.3.2. ネイティブモードでの @QuarkusIntegrationTest

ネイティブモードでは、@QuarkusIntegrationTest のアノテーションが付けられたテストは、実行中のネイティブアプリケーションとは別のプロセスでホストされている JVM で実行されます。

この重要な結果として、テストとネイティブアプリケーション間のすべての通信は、次の 1 つ以上の形式を取る必要があります。

  • ネットワークの呼び出し。通常は、HTTP またはアプリケーションがサポートするその他のネットワークプロトコルです。
  • ファイルシステムの変更を監視します。(例: Camel file エンドポイント経由)
  • その他の種類のプロセス間通信。

QuarkusIntegrationTest は、@QuarkusTest では利用できない追加機能を提供します。

  • JVM モードでは、Quarkus ビルドによって生成された実行可能なアプリケーション JAR を起動してテストできます。
  • ネイティブモードでは、Quarkus ビルドによって作成されたネイティブアプリケーションを起動してテストできます。
  • コンテナーイメージをビルドに追加すると、コンテナーが起動し、それに対してテストが実行されます。

QuarkusIntegrationTest の詳細は、Quarkus testing guide を参照してください。

4.1.4. 外部サービスによるテスト

4.1.4.1. Testcontainers

アプリケーションは、メッセージングブローカー、データベース、その他のサービスなどの外部リソースにアクセスする必要がある場合があります。

対象のサービスのコンテナーイメージが利用可能な場合は、Testcontainers を使用して、テスト中にサービスを起動および設定できます。

4.1.4.1.1. QuarkusTestResourceLifecycleManager を使用して設定データを渡す

アプリケーションを正常に動作させるためには、多くの場合、接続設定データ (ホスト、ポート、ユーザー、リモートサービスのパスワード) をアプリケーションの起動前に渡すことが不可欠です。

Quarkus エコシステムでは、QuarkusTestResourceLifecycleManager がこの目的を果たします。

start() メソッドで 1 つ以上の Testcontainer を起動し、メソッドから接続設定を Map の形式で返すことができます。

このマップのエントリーは、モードに応じてさまざまな方法でアプリケーションに渡されます。

  • ネイティブモード: コマンドライン (-Dkey=value)
  • JVM モード: 特別な MicroProfile 設定プロバイダー
注記

コマンドラインおよび MicroProfile 設定は、application.properties ファイルの設定よりも優先されます。

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

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;

public class MyTestResource implements QuarkusTestResourceLifecycleManager {

    private GenericContainer<?> myContainer;

    @Override
    public Map<String, String> start() {
        // Start the needed container(s)
        myContainer = new GenericContainer(DockerImageName.parse("my/image:1.0.0"))
                .withExposedPorts(1234)
                .waitingFor(Wait.forListeningPort());

        myContainer.start();

        // Pass the configuration to the application under test
        // You can also pass camel component property names / values to automatically configure Camel components
        return new HashMap<>() {{
                put("my-container.host", container.getHost());
                put("my-container.port", "" + container.getMappedPort(1234));
        }};
    }

    @Override
    public void stop() {
        // Stop the needed container(s)
        myContainer.stop();
        ...
    }
}
Copy to Clipboard

@QuarkusTestResource を使用して、テストクラスから定義済みのテストリソースを参照します。

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
@QuarkusTestResource(MyTestResource.class)
class MyTest {
   ...
}
Copy to Clipboard
ヒント

サンプル実装は Camel Quarkus ソースにあります。

4.1.4.2. WireMock

ライブエンドポイントが利用できない、信頼性が低い、コストがかかる場合などには、テストをライブエンドポイントに接続する代わりに、サードパーティーのサービスおよび API との HTTP インタラクションをスタブできます。

WireMock を使用すると、HTTP インタラクションをモックおよび記録できます。これは、さまざまなコンポーネントエクステンション用に Camel Quarkus テストスイート全体で広く使用されています。

4.1.4.2.1. WireMock のセットアップ

手順

  1. WireMock サーバーをセットアップします。

    注記

    テストを行う Camel コンポーネントを常に設定して、すべての HTTP 対話を WireMock プロキシー経由で渡すようにします。これは、API エンドポイント URL を決定するコンポーネントプロパティーを設定することで実現できます。

    import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
    import static com.github.tomakehurst.wiremock.client.WireMock.get;
    import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
    import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import com.github.tomakehurst.wiremock.WireMockServer;
    
    import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
    
    public class WireMockTestResource implements QuarkusTestResourceLifecycleManager {
    
        private WireMockServer server;
    
        @Override
        public Map<String, String> start() {
            // Setup & start the server
            server = new WireMockServer(
                wireMockConfig().dynamicPort()
            );
            server.start();
    
            // Stub an HTTP endpoint. WireMock also supports a record and playback mode
            // https://wiremock.org/docs/record-playback/
            server.stubFor(
                get(urlEqualTo("/api/greeting"))
                    .willReturn(aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody("{\"message\": \"Hello World\"}")));
    
            // Ensure the camel component API client passes requests through the WireMock proxy
            Map<String, String> conf = new HashMap<>();
            conf.put("camel.component.foo.server-url", server.baseUrl());
            return conf;
        }
    
        @Override
        public void stop() {
            if (server != null) {
                server.stop();
            }
        }
    }
    Copy to Clipboard
  2. テストクラスに @QuarkusTestResource アノテーションがあり、適切なテストリソースクラスが値として指定されていることを確認します。WireMock サーバーは、すべてのテストが実行される前に起動され、すべてのテストが終了するとシャットダウンされます。
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
@QuarkusTestResource(WireMockTestResource.class)
class MyTest {
   ...
}
Copy to Clipboard

WireMock サーバーは、すべてのテストが実行される前に起動し、すべてのテストが終了するとシャットダウンします。

ヒント

サンプルの実装は、Camel Quarkus 統合テストソースツリーにあります。

4.1.5. CamelQuarkusTestSupport での CamelTestSupport スタイルのテスト

Camel Quarkus 2.13.0 以降、CamelQuarkusTestSupport をテストに使用できます。これは CamelTestSupport の後継で、Quarkus では適切に機能しません。

重要

CamelQuarkusTestSupport は、JVM モードでのみ機能します。ネイティブモードでテストする必要がある場合は、上記の代替テストストラテジーのいずれかを使用します。

4.1.5.1. JVM モードでの CamelQuarkusTestSupport によるテスト

次の依存関係をモジュール (できれば test スコープ内) に追加します。

<dependency>
    <groupId>org.apache.camel.quarkus</groupId>
    <artifactId>camel-quarkus-junit5</artifactId>
    <scope>test</scope>
</dependency>
Copy to Clipboard

次のように、テストで CamelQuarkusTestSupport を使用できます。

@QuarkusTest
@TestProfile(SimpleTest.class) //necessary only if "newly created" context is required for the test (worse performance)
public class SimpleTest extends CamelQuarkusTestSupport {
    ...
}
Copy to Clipboard

4.1.5.2. テスト用の CamelContext のカスタマイズ

設定プロファイル、CDI Bean、オブザーバー、mocks などを使用してテスト用に CamelContext をカスタマイズできます。createCamelContext メソッドをオーバーライドして、CamelContext と直接対話することもできます。

重要

createCamelContext を使用する場合は、新しい CamelContext をインスタンス化して返さ ないようにしてください。代わりに、super.createCamelContext() を呼び出して、返された CamelContext を必要に応じて変更します。このルールに従わないと、例外が発生します。

@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {

    @Override
    protected CamelContext createCamelContext() throws Exception {
        // Must call super to get a handle on the application scoped CamelContext
        CamelContext context = super.createCamelContext();
        // Apply customizations
        context.setTracing(true);
        // Return the modified CamelContext
        return context;
    }
}
Copy to Clipboard

4.1.5.3. テスト用のルートの設定

アプリケーション内の RouteBuilder を拡張するすべてのクラスのルートは、CamelContext に自動的に追加されます。同様に、camel.main.routes-include-pattern から設定された XML または YAML ルートも読み込まれます。

これは必ずしもテストに適切であるとは限りません。設定プロパティーを使用して、テスト時にどのルートをロードするかを制御します。

  • quarkus.camel.routes-discovery.include-patterns
  • quarkus.camel.routes-discovery.exclude-patterns
  • camel.main.routes-include-pattern
  • camel.main.routes-exclude-pattern

createRouteBuilder をオーバーライドして、テストクラスごとにテスト固有のルートを定義することもできます。

@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
    @Test
    void testGreeting() {
        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
        mockEndpoint.expectedBodiesReceived("Hello World");

        template.sendBody("direct:start", "World");

        mockEndpoint.assertIsSatisified();
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:start")
                    .transform().simple("Hello ${body}")
                    .to("mock:result");
            }
        };
    }
}
Copy to Clipboard

4.1.5.4. CamelContext テストライフサイクル

CamelTestSupport と比較した CamelQuarkusTestSupport の主な違いの 1 つは、CamelContext ライフサイクルがどのように管理されるかです。

Camel Quarkus では、ランタイムによって単一の CamelContext が自動的に作成されます。デフォルトでは、この CamelContext はすべてのテスト間で共有され、これは、テストスイート全体が実行中は起動状態のままになります。

これにより、テストに予期しない副作用が生じる可能性があります。テスト間で CamelContext を再起動する必要がある場合は、カスタム テストプロファイル を作成して、テスト対象のアプリケーションを強制的に再起動できます。

たとえば、テストプロファイルを定義するには、次のようにします。

@QuarkusTest
class MyTestProfile implements QuarkusTestProfile {
    ...
}
Copy to Clipboard

次に、@TestProfile を使用してテストクラスで参照します。

// @TestProfile will trigger the application to be restarted
@TestProfile(MyTestProfile.class)
@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
    ...
}
Copy to Clipboard
注記

CamelContextstop() メソッドと start() メソッドを呼び出して手動で再起動できません。これにより、例外が発生します。

4.1.5.5. 例

4.1.5.5.1. シンプルな RouteBuilder およびテストクラス

シンプルな RouteBuilder:

public class MyRoutes extends RouteBuilder {
    @Override
    public void configure() {
        from("direct:start")
            .transform().simple("Hello ${body}")
            .to("mock:result");
    }
}
Copy to Clipboard

メッセージペイロードを direct:start エンドポイントに送信するテストを実行します。

@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
    @Test
    void testGreeting() {
        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
        mockEndpoint.expectedBodiesReceived("Hello World");

        template.sendBody("direct:start", "World");

        mockEndpoint.assertIsSatisified();
    }
}
Copy to Clipboard
4.1.5.5.2. AdviceWith の使用
@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
    @BeforeEach
    public void beforeEach() throws Exception {
        AdviceWith.adviceWith(this.context, "advisedRoute", route -> {
            route.replaceFromWith("direct:replaced");
        });
    }

    @Override
    protected RoutesBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:start").routeId("advisedRoute")
                    .transform().simple("Hello ${body}")
                    .to("mock:result");
            }
        };
    }

    @Test
    void testAdvisedRoute() throws Exception {
        MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
        mockEndpoint.expectedBodiesReceived("Hello World");

        template.sendBody("direct:replaced", "World");

        mockEndpoint.assertIsSatisfied();
    }
}
Copy to Clipboard
4.1.5.5.3. アドバイスの明示的な有効化

アドバイスを明示的に有効にする 場合は、AdviceWith のセットアップを完了するときに startRouteDefinitions を呼び出す必要があります。

注記

startRouteDefinitions を呼び出す必要があるのは、アドバイスされて いない ルートが設定されている場合のみです。

4.1.5.6. 制限

4.1.5.6.1. CamelTestSupport から継承されたテストライフサイクルメソッド

CamelQuarkusTestSupport は、CamelTestSupport から一部のテストライフサイクルメソッドを継承します。ただし、これらは使用すべきではなく、代わりに CamelQuarkusTestSupport の同等のメソッドに置き換えられます。

CamelTestSupport ライフサイクルメソッドCamelQuarkusTestSupport 相当

afterAll

doAfterAll

afterEach, afterTestExecution

doAfterEach

beforeAll

doAfterConstruct

beforeEach

doBeforeEach

4.1.5.6.2. カスタム Camel レジストリーの作成はサポートされていません

createCamelRegistryCamelQuarkusTestSupport 実装は UnsupportedOperationException を出力します。

オブジェクトを Camel レジストリーにバインドまたはバインド解除する必要がある場合は、次のいずれかの方法で実行できます。

  • 名前付き CDI Bean を生成する

    public class MyBeanProducers {
        @Produces
        @Named("myBean")
        public MyBean createMyBean() {
            return new MyBean();
        }
    }
    Copy to Clipboard
  • createCamelContext をオーバーライドし (上記の例を参照)、camelContext.getRegistry().bind ("foo"、fooBean) を呼び出す。
  • @BindToRegistry アノテーションを使用する。

    @QuarkusTest
    class SimpleTest extends CamelQuarkusTestSupport {
        @BindToRegistry("myBean")
        MyBean myBean = new MyBean();
    }
    Copy to Clipboard
    注記

    個々のテストクラスから Camel レジストリーにバインドされた Bean は、テストスイートの実行中は保持されます。テストの期待値によっては、予期しない結果が生じる可能性があります。これを回避するには、テストプロファイルを使用して CamelContext を再起動できます。

トップに戻る
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

Theme

© 2025 Red Hat