Apache Camel Advent Calendar 6日目の記事は、サポート担当古市が担当します。(鎌田さん、アドバイスありがとうございます。) テーマは、「Testing Camel」

Camel は、JUnit extension ライブラリーを提供しており、従来のテストコードと同等に Camelルート用テストコードを記述可能です。 camel.apache.org テストの粒度をこのように分けることで、テスト設計がし易くなるでしょう。
- processor/Beans単位
- Camelルート単位
Processor/Beans単位
例えばこのような Processor を実装したいとします。
public class CustomProcessor implements Processor {
@SuppressWarnings("unchecked")
@Override
public void process(Exchange exchange) throws Exception {
exchange.getMessage().setBody("${body} from ${header.username}");
}
camel route単位でのテストでは無いので、mockitoが提供する @InjectMocks を使い、テスト対象の Processorのみ用意します。 site.mockito.org
@InjectMocks CustomProcessor processor;
テストでは、org.apache.camel.builder.ExchangeBuilderクラスを使い、意図した exchangeオブジェクトを作成し、Processor/Bean へ投入することが可能です。
org.apache.camel.CamelContextcamelContext = new org.apache.camel.impl.DefaultCamelContext();
org.apache.camel.Exchange exchange = ExchangeBuilder.anExchange(camelContext)
.withBody("Hello World!")
.withHeader("username", "Bob")
.build();
processor.process(exchange);
assertEquals("Hello World! from Bob", exchange.getMessage().getBody());
Camelルート単位
camelルート単位のテストをしたい場合、endpointをモックへ置き換える方法が有用です。 テスト用に別途モックへ置き換えた camel routeを用意するのは手間なので、adviceWith を使い、特定 endpointをモックに置き換えます。 具体的には、RouteBuilder を拡張した AdviceWithRouteBuilder の .configure()メソッド内にて、ID指定により特定エンドポイントをモックに置き換えたり、モックエンドポイントを追加することも可能です。 camel.apache.org コミュニティーページで紹介されているコードに注目します。
AdviceWith.adviceWith(context, "myRoute", new AdviceWithRouteBuilder() {
@Override
public void configure() throws Exception {
weaveAddLast().to("mock:result");
}
});
ウィーブ(織り込む)したい対象ルートID "myRoute" を指定し、ルート末尾にモックエンドポイント mock:result を追加しています。 ラムダ形式で記述も可能です。
AdviceWith.adviceWith(context, "myRoute", a ->
a.weaveAddLast().to("mock:result")
);
テストでは、モックエンドポイントの状態を捕捉しテスト判定に使用することができます。
getMockEndpoint("mock:result").expectedMessageCount(3);
MockEndpoint.assertIsSatisfied(context);
モックに指定できる判定方法は多岐にわたります。常に最新バージョンの javadoc をウォッチすることをお勧めします。 javadoc.io
よく使うであろうメソッドをもう1つ紹介します。
expectedMessagesMatches(org.apache.camel.Predicate... predicates)
期待する exchangeの状態を判定することが可能です。以下のように実装します。
getMockEndpoint("mock:result").expectedMessagesMatches(
exchange -> {
Object body = exchange.getMessage().getBody();
return (body instanceof String s)
&& s.equals("Hello World"));
});
Fileオブジェクトなど、想定するオブジェクトに置き換えて評価式の実装をご検討ください。
Quarkus runtime をご利用予定の場合、CamelQuarkusTestSupport が提供されておりますので、こちらも要チェックです。 camel.apache.org
サンプルコードにあるよう、既に用意された ProducerTemplateを使い、メッセージを投入することができます。
@QuarkusTest
class SimpleTest extends CamelQuarkusTestSupport {
@Test
void testGreeting() {
MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
mockEndpoint.expectedBodiesReceived("Hello World");
template.sendBody("direct:start", "World");
mockEndpoint.assertIsSatisfied();
}
もちろん CamelSpringTestSupport も、SpringBoot runtime向けに用意されています。 camel.apache.org
明日の advent calendar 7日目では、「Debugging Camel」 についてご紹介します。 アドベントカレンダーの一覧はこちらです。 qiita.com