第107章 Mock


Mock コンポーネント

Mock コンポーネントは、強力な宣言型テストメカニズムを提供します。これは、テストの開始前に Mock エンドポイントで宣言的期待を作成できるという点で jMock と似ています。次に、テストが実行されます。これは通常、1 つ以上のエンドポイントに対してメッセージを実行し、最終的にはシステムが期待どおりに機能するようにテストケースで期待をアサートできます。
これにより、以下のようなさまざまなことをテストできます。
  • 正しい数のメッセージが各エンドポイントで受信されます。
  • 正しいペイロードが適切な順序で受信されます。
  • メッセージは、一部の を使用して注文テスト関数を作成し、順番にエンドポイントに到達します。
  • メッセージは、特定のヘッダーに特定の値がある場合や、そのメッセージのパーツが XPath または XQuery Expression を評価するなど、一部の述語と一致するなど、何らかの述語に一致します。http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/Predicate.html
Mock エンドポイントである Test エンドポイント もありますが、2 番目のエンドポイントを使用して想定されるメッセージ本文のリストを提供し、Mock エンドポイントアサーションを自動的に設定します。つまり、File または データベース の一部のサンプルメッセージからアサーションを自動的に設定する Mock エンドポイントです。以下に例を示します。
Mock エンドポイントは受信したエクスチェンジをメモリーに無期限に保持します。
Mock はテスト用に設計されていることに注意してください。Mock エンドポイントをルートに追加すると、エンドポイントに送信された各 エクスチェンジ は、明示的にリセットするか JVM が再起動するまで、メモリーに保存されます(後続の検証を許可します)。高いボリュームや大きなメッセージを送信する場合は、メモリーを過剰に使用する可能性があります。目的が deployable ルートをインラインでテストする場合は、Mock エンドポイントをルートに直接追加するのではなく、テストで NotifyBuilder または AdviceWith を使用することを検討してください。
Camel 2.10 以降では、2 つの新しいオプションが retainFirstretainLast の 2 つあり、Mock エンドポイントがメモリー内に保持するメッセージの数を制限するために使用できます。

URI 形式

mock:someName[?options]
Copy to Clipboard Toggle word wrap
someName には、エンドポイントを一意に識別する任意の文字列を指定できます。
URI にクエリーオプションは ?option=value&option=value&.. の形式で追加できます。

オプション

Expand
オプション デフォルト 説明
reportGroup null レポートに スループットロガー を使用するサイズ
retainFirst
Camel 2.10: メモリーの最初の X 個のメッセージのみを保持します。
retainLast
Camel 2.10: 最後の X 個のメッセージのみをメモリーに保持します。

簡単な例

以下は、使用中の Mock エンドポイントの例です。まず、エンドポイントがコンテキストで解決されます。その後、期待値を設定し、テストの実行後に、期待値が満たされていることをアサートします。
MockEndpoint resultEndpoint = context.resolveEndpoint("mock:foo", MockEndpoint.class);

resultEndpoint.expectedMessageCount(2);

// send some messages
...

// now lets assert that the mock:foo endpoint received 2 messages
resultEndpoint.assertIsSatisfied();
Copy to Clipboard Toggle word wrap
通常 は assertIsSatisfied ()メソッドを呼び出して、テスト実行後に期待が満たされていることをテストします。
Apache Camel はデフォルトで assertIsSatisfied () が呼び出されると 10 秒待機します。これは setResultWaitTime (millis) メソッドを設定することで設定できます。

assertPeriod の使用

Camel 2.7 で利用可能 アサーションが満たされると、Camel は assertIsSatisfied メソッドの 待機を停止し、続行します。つまり、新しいメッセージがモックエンドポイント(後でのみ)に到達すると、アサーションの結果には影響を与えません。その後の期間後に新しいメッセージが到達しないことをテストする場合は、以下のように setAssertPeriod メソッドを設定してこれを実行できます。
MockEndpoint resultEndpoint = context.resolveEndpoint("mock:foo", MockEndpoint.class);
resultEndpoint.setAssertPeriod(5000);
resultEndpoint.expectedMessageCount(2);

// send some messages
...

// now lets assert that the mock:foo endpoint received 2 messages
resultEndpoint.assertIsSatisfied();
Copy to Clipboard Toggle word wrap

期待値の設定

MockEndpoint の javadoc から、期待を設定するために使用できるさまざまなヘルパーメソッドを確認できます。主なメソッドは以下のとおりです。
Expand
メソッド 説明
expectedMessageCount(int) エンドポイントで想定されるメッセージ数を定義します。
expectedMinimumMessageCount(int) エンドポイントで想定されるメッセージの最小数を定義します。
expectedBodiesReceived(...) 受信すべき想定されるボディーを定義します(順番に)。
expectedHeaderReceived(...) 受信する必要のあるヘッダーを定義する
expectsAscending(Expression) メッセージの順序を追加するには、指定の を使用してメッセージを比較することで、メッセージが順番に受信されることを想定します。
expectsDescending(Expression) メッセージの順序を追加するには、指定の を使用してメッセージを比較することで、メッセージが順番に受信されることを想定します。
expectsNoDuplicates(Expression) 重複メッセージが受信されないことを期待するには、 を使用して各メッセージの一意の識別子を計算します。JMS を使用している場合は JMSMessageID やメッセージ内の一意の参照番号などになります。
以下は別の例です。
resultEndpoint.expectedBodiesReceived("firstMessageBody", "secondMessageBody", "thirdMessageBody");
Copy to Clipboard Toggle word wrap

特定のメッセージへの期待の追加

さらに、message (int messageIndex) メソッドを使用して、受信される特定のメッセージに関するアサーションを追加できます。
たとえば、最初のメッセージのヘッダーまたはボディーに期待値を追加するには( java.util.Listなどのゼロベースのインデックスを使用)、以下のコードを使用できます。
resultEndpoint.message(0).header("foo").isEqualTo("bar");
Copy to Clipboard Toggle word wrap
camel-core プロセッサーテスト で使用される Mock エンドポイントの例がいくつかあります。

既存エンドポイントのモック化

Camel 2.7 以降で利用可能
Camel では、Camel ルート内の既存のエンドポイントを自動的にモック化できるようになりました。
仕組み
重要: エンドポイントは動作中ですが、Mock エンドポイントがインジェクトされ、最初にメッセージを受信してから、メッセージをターゲットエンドポイントに委譲することです。これは、インターセプトおよびデリゲートまたはエンドポイントリスナーとして表示できます。
指定のルートがある場合には、以下を実行します。
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
    return new RouteBuilder() {
        @Override
        public void configure() throws Exception {
            from("direct:start").to("direct:foo").to("log:foo").to("mock:result");

            from("direct:foo").transform(constant("Bye World"));
        }
    };
}
Copy to Clipboard Toggle word wrap
その後、以下のように Camel の adviceWith 機能を使用して、ユニットテストから指定のルートにあるすべてのエンドポイントをモック化できます。
public void testAdvisedMockEndpoints() throws Exception {
    // advice the first route using the inlined AdviceWith route builder
    // which has extended capabilities than the regular route builder
    context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
        @Override
        public void configure() throws Exception {
            // mock all endpoints
            mockEndpoints();
        }
    });

    getMockEndpoint("mock:direct:start").expectedBodiesReceived("Hello World");
    getMockEndpoint("mock:direct:foo").expectedBodiesReceived("Hello World");
    getMockEndpoint("mock:log:foo").expectedBodiesReceived("Bye World");
    getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");

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

    assertMockEndpointsSatisfied();

    // additional test to ensure correct endpoints in registry
    assertNotNull(context.hasEndpoint("direct:start"));
    assertNotNull(context.hasEndpoint("direct:foo"));
    assertNotNull(context.hasEndpoint("log:foo"));
    assertNotNull(context.hasEndpoint("mock:result"));
    // all the endpoints was mocked
    assertNotNull(context.hasEndpoint("mock:direct:start"));
    assertNotNull(context.hasEndpoint("mock:direct:foo"));
    assertNotNull(context.hasEndpoint("mock:log:foo"));
}
Copy to Clipboard Toggle word wrap
モックエンドポイントには uri mock:<endpoint> が指定されることに 注意してください(例: mock:direct:foo )。INFO レベルの Camel ログで、モックされるエンドポイントは以下のようになります。
INFO  Adviced endpoint [direct://foo] with mock endpoint [mock:direct:foo]

Copy to Clipboard Toggle word wrap
モックされたエンドポイントはパラメーターがありません。
モックされたエンドポイントには、パラメーターが取り除かれます。たとえば、エンドポイント "log:foo?showAll=true" は、次のエンドポイントである "mock:log:foo" にモックされます。パラメーターが削除されたことに注意してください。
パターンを使用して特定のエンドポイントのみをモックすることもできます。たとえば、次のように行うすべての ログ エンドポイントをモック化するには、以下を実行します。
public void testAdvisedMockEndpointsWithPattern() throws Exception {
    // advice the first route using the inlined AdviceWith route builder
    // which has extended capabilities than the regular route builder
    context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
        @Override
        public void configure() throws Exception {
            // mock only log endpoints
            mockEndpoints("log*");
        }
    });

    // now we can refer to log:foo as a mock and set our expectations
    getMockEndpoint("mock:log:foo").expectedBodiesReceived("Bye World");

    getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");

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

    assertMockEndpointsSatisfied();

    // additional test to ensure correct endpoints in registry
    assertNotNull(context.hasEndpoint("direct:start"));
    assertNotNull(context.hasEndpoint("direct:foo"));
    assertNotNull(context.hasEndpoint("log:foo"));
    assertNotNull(context.hasEndpoint("mock:result"));
    // only the log:foo endpoint was mocked
    assertNotNull(context.hasEndpoint("mock:log:foo"));
    assertNull(context.hasEndpoint("mock:direct:start"));
    assertNull(context.hasEndpoint("mock:direct:foo"));
}
Copy to Clipboard Toggle word wrap
サポートされるパターンはワイルドカードまたは正規表現になります。詳細は、Camel で使用される一致関数として Intercept を参照してください。
重要
エンドポイントをモックすると、メッセージがモックに到達するとコピーされることに注意してください。つまり、Camel はより多くのメモリーを使用します。これは、多くのメッセージで を送信する場合、適切ではない可能性があります。

camel-test コンポーネントを使用した既存エンドポイントのモック化

adviceWith を使用して Camel にエンドポイントをモックするように指示する代わりに、camel-test Test Kit を使用する際にこの動作を簡単に有効にできます。同じルートを以下のようにテストできます。isMockEndpoints メソッドから "*" を返すことに注意してください。これは、Camel にすべてのエンドポイントをモックするように指示します。すべての ログ エンドポイントのみをモック化したい場合は、代わりに log*" を返すことができます。
public class IsMockEndpointsJUnit4Test extends CamelTestSupport {

    @Override
    public String isMockEndpoints() {
        // override this method and return the pattern for which endpoints to mock.
        // use * to indicate all
        return "*";
    }

    @Test
    public void testMockAllEndpoints() throws Exception {
        // notice we have automatic mocked all endpoints and the name of the endpoints is "mock:uri"
        getMockEndpoint("mock:direct:start").expectedBodiesReceived("Hello World");
        getMockEndpoint("mock:direct:foo").expectedBodiesReceived("Hello World");
        getMockEndpoint("mock:log:foo").expectedBodiesReceived("Bye World");
        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");

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

        assertMockEndpointsSatisfied();

        // additional test to ensure correct endpoints in registry
        assertNotNull(context.hasEndpoint("direct:start"));
        assertNotNull(context.hasEndpoint("direct:foo"));
        assertNotNull(context.hasEndpoint("log:foo"));
        assertNotNull(context.hasEndpoint("mock:result"));
        // all the endpoints was mocked
        assertNotNull(context.hasEndpoint("mock:direct:start"));
        assertNotNull(context.hasEndpoint("mock:direct:foo"));
        assertNotNull(context.hasEndpoint("mock:log:foo"));
    }

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:start").to("direct:foo").to("log:foo").to("mock:result");

                from("direct:foo").transform(constant("Bye World"));
            }
        };
    }
}
Copy to Clipboard Toggle word wrap

XML DSL を使用した既存エンドポイントのモック化

ユニットテストに camel-test コンポーネントを使用しない場合(上記のように)、ルートに XML ファイルを使用する場合に別のアプローチを使用できます。解決策は、ユニットテストで使用する新しい XML ファイルを作成し、テストするルートを持つ目的の XML ファイルを含めることです。
camel-route.xml ファイルにルートがあるとします。
<!-- this camel route is in the camel-route.xml file -->
<camelContext xmlns="http://camel.apache.org/schema/spring">

    <route>
        <from uri="direct:start"/>
        <to uri="direct:foo"/>
        <to uri="log:foo"/>
        <to uri="mock:result"/>
    </route>

    <route>
        <from uri="direct:foo"/>
        <transform>
            <constant>Bye World</constant>
        </transform>
    </route>

</camelContext>
Copy to Clipboard Toggle word wrap
次に、以下のように新しい XML ファイルを作成します。ここで、camel-route.xml ファイルが含まれ、org.apache.camel.impl.InterceptSendToMockEndpointStrategy クラスで Spring Bean を定義します。これは、Camel に対してすべてのエンドポイントをモック化するように指示します。
<!-- the Camel route is defined in another XML file -->
<import resource="camel-route.xml"/>

<!-- bean which enables mocking all endpoints -->
<bean id="mockAllEndpoints" class="org.apache.camel.impl.InterceptSendToMockEndpointStrategy"/>
Copy to Clipboard Toggle word wrap
その後、ユニットテストで camel-route.xml の代わりに新しい XML ファイル(test- camel-route.xml )を読み込みます。
すべての ログ エンドポイントのみをモック化するには、Bean のコンストラクターでパターンを定義できます。
<bean id="mockAllEndpoints" class="org.apache.camel.impl.InterceptSendToMockEndpointStrategy">
    <constructor-arg index="0" value="log*"/>
</bean>
Copy to Clipboard Toggle word wrap

エンドポイントのモック化および元のエンドポイントへの送信を省略する

Camel 2.10 以降で利用可能
特定のエンドポイントへのモック化や送信を簡単にスキップしたい場合があります。そのため、メッセージはデーストされ、モックエンドポイントのみに送信されます。Camel 2.10 以降では、AdviceWith または Test Kit を使用して mockEndpointsAndSkip メソッドを使用できるようになりました。以下の例では、direct:foo と direct:bar の 2 つのエンドポイントへ の送信を省略します
public void testAdvisedMockEndpointsWithSkip() throws Exception {
    // advice the first route using the inlined AdviceWith route builder
    // which has extended capabilities than the regular route builder
    context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
        @Override
        public void configure() throws Exception {
            // mock sending to direct:foo and direct:bar and skip send to it
            mockEndpointsAndSkip("direct:foo", "direct:bar");
        }
    });

    getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
    getMockEndpoint("mock:direct:foo").expectedMessageCount(1);
    getMockEndpoint("mock:direct:bar").expectedMessageCount(1);

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

    assertMockEndpointsSatisfied();

    // the message was not send to the direct:foo route and thus not sent to the seda endpoint
    SedaEndpoint seda = context.getEndpoint("seda:foo", SedaEndpoint.class);
    assertEquals(0, seda.getCurrentQueueSize());
}
Copy to Clipboard Toggle word wrap
Test Kitを使用した同じ例
public class IsMockEndpointsAndSkipJUnit4Test extends CamelTestSupport {

    @Override
    public String isMockEndpointsAndSkip() {
        // override this method and return the pattern for which endpoints to mock,
        // and skip sending to the original endpoint.
        return "direct:foo";
    }

    @Test
    public void testMockEndpointAndSkip() throws Exception {
        // notice we have automatic mocked the direct:foo endpoints and the name of the endpoints is "mock:uri"
        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
        getMockEndpoint("mock:direct:foo").expectedMessageCount(1);

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

        assertMockEndpointsSatisfied();

        // the message was not send to the direct:foo route and thus not sent to the seda endpoint
        SedaEndpoint seda = context.getEndpoint("seda:foo", SedaEndpoint.class);
        assertEquals(0, seda.getCurrentQueueSize());
    }

    @Override
    protected RouteBuilder createRouteBuilder() throws Exception {
        return new RouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("direct:start").to("direct:foo").to("mock:result");

                from("direct:foo").transform(constant("Bye World")).to("seda:foo");
            }
        };
    }
}
Copy to Clipboard Toggle word wrap

保持するメッセージ数の制限

Camel 2.10 以降で利用可能
Mock エンドポイントは、デフォルトで受信したすべての エクスチェンジ のコピーを保持します。したがって、大量のメッセージをテストすると、メモリーを消費します。Camel 2.10 以降では、2 つのオプション retainFirst および retainLast を導入しました。これを使用して、最初と最後の エクスチェンジの N 分のみを保持するために使用できます。
以下のコードでは、最初の 5 つと最後の 5 エクスチェンジのコピーを保持するだけです。
  MockEndpoint mock = getMockEndpoint("mock:data");
  mock.setRetainFirst(5);
  mock.setRetainLast(5);
  mock.expectedMessageCount(2000);

  ...

  mock.assertIsSatisfied();
Copy to Clipboard Toggle word wrap
この使用にはいくつかの制限があります。MockEndpointgetExchanges ( )メソッドおよび getReceivedExchanges () メソッドは、エクスチェンジの保持コピーのみを 返します。上記の例では、リストには 10 エクスチェンジ(最初の 5 つ、および最後の 5)が含まれます。retainFirst オプションおよび retainLast オプションには、使用可能な想定されるメソッドの制限もあります。たとえば、メッセージボディーやヘッダーなどで機能する予定のXXX メソッドは、保持済みメッセージでのみ動作します。上記の例では、10 個の保持済みメッセージのみについてテストできます。

到着時間でのテスト

Camel 2.7 以降で利用可能
Mock エンドポイントは、メッセージの到着時間を Exchange のプロパティーとして保存します。
Date time = exchange.getProperty(Exchange.RECEIVED_TIMESTAMP, Date.class);
Copy to Clipboard Toggle word wrap
この情報を使用して、メッセージがモックに到達するタイミングを確認することができます。ただし、以前のメッセージと次のメッセージがモックに到達する間隔を把握するための基盤も提供します。これを使用して、Mock エンドポイントで DSL に 到達 して期待を設定できます。
たとえば、最初のメッセージが、次に行う前に 0-2 秒の間に到着するように設定するには、次のコマンドを実行します。
mock.message(0).arrives().noLaterThan(2).seconds().beforeNext();
Copy to Clipboard Toggle word wrap
また、これを 2 番目のメッセージ(0 インデックスベース)が前のメッセージから 0-2 秒より後に到達しないように定義することもできます。
mock.message(1).arrives().noLaterThan(2).seconds().afterPrevious();
Copy to Clipboard Toggle word wrap
between を使用して下限を設定することもできます。たとえば、1-4 秒の間にあるとします。
mock.message(1).arrives().between(1, 4).seconds().afterPrevious();
Copy to Clipboard Toggle word wrap
たとえば、メッセージ間のギャップが最大 1 秒であることを示すために、すべてのメッセージに期待値を設定することもできます。
mock.allMessages().arrives().noLaterThan(1).seconds().beforeNext();
Copy to Clipboard Toggle word wrap
時間単位
上記の例では、時間単位として を使用しますが、Camel には ミリ 秒、および もあります。
トップに戻る
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

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

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

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

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

会社概要

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

Theme

© 2025 Red Hat