Apache Camel单元测试如何过滤路由仅启用指定路由
问题背景
需要在Apache Camel单元测试中仅加载启用指定路由,例如仅加载ID为my-translation-route的路由,被测路由定义如下:
public class TestRoute extends RouteBuilder { @Override public void configure() { from("ftp://my-ftp-server:21/messages") .routeId("my-inbound-route") .to("direct:my-translation-route"); from("direct:my-translation-route") .routeId("my-translation-route") .bean(MyBean.class) .to("direct:my-outbound-route"); from ("direct:my-outbound-route") // 注意:原代码此处routeId与其他路由重复,会导致路由匹配异常 .routeId("my-outbound-route") .to("http://my-http-server:8080/messages"); } }
此前尝试调用Model#filterRoutes、context.setRouteFilterPattern做路由过滤未生效,所有路由仍会全量加载,对应测试代码如下:
class TestRouteTest extends CamelTestSupport { @Override protected RoutesBuilder createRouteBuilder() { return new TestRoute(); } @Override public boolean isUseAdviceWith() { return true; } @Test void testIfItWorks() throws Exception { context.setRouteFilterPattern("my-translation-route", null); AdviceWith.adviceWith(context, "my-translation-route", a -> { a.mockEndpointsAndSkip("direct:my-outbound-route"); }); context.start(); getMockEndpoint("mock:direct:my-outbound-route").expectedBodyReceived().expression(constant("Hahaha! 42")); template.sendBodyAndHeaders("direct:my-translation-route", "42", null); assertMockEndpointsSatisfied(); } }
目前已知重写CamelTestSupport#getRouteFilterIncludePattern可实现路由过滤:
@Override public String getRouteFilterIncludePattern() { return "my-translation-route"; }
但该配置会作用于测试类下所有测试方法,无法满足单测试方法粒度的路由加载控制需求。
失效原因
context.setRouteFilterPattern不生效的核心原因:路由过滤逻辑是在Camel上下文启动阶段、解析RouteBuilder路由定义时执行的,测试方法内调用set方法时,所有路由定义已经完成解析加载,再设置过滤规则不会生效。
重写getRouteFilterIncludePattern属于上下文初始化前加载的类级配置,因此默认对类下所有测试方法生效。
可落地方案
方案1:用AdviceWith在上下文启动前移除非目标路由
开启isUseAdviceWith()=true时,可在context.start()前通过AdviceWith直接删除/替换不需要的路由,不需要依赖全局过滤规则,配置仅对当前测试方法生效:
@Test void testOnlyTranslationRoute() throws Exception { // 移除不需要的入站路由 AdviceWith.adviceWith(context, "my-inbound-route", AdviceWithBuilder::remove); // 移除不需要的出站路由,也可以按测试需求替换from端点、mock端点 AdviceWith.adviceWith(context, "my-outbound-route", AdviceWithBuilder::remove); // 织入目标路由的测试逻辑 AdviceWith.adviceWith(context, "my-translation-route", a -> { a.mockEndpointsAndSkip("direct:my-outbound-route"); }); context.start(); getMockEndpoint("mock:direct:my-outbound-route") .expectedBodyReceived().expression(constant("Hahaha! 42")); template.sendBody("direct:my-translation-route", "42"); assertMockEndpointsSatisfied(); }
注意:删除路由前要确认目标路由和被删路由没有强依赖,否则上下文启动会抛出依赖缺失异常。
方案2:上下文启动前在测试方法内设置过滤规则
CamelTestSupport默认会为每个测试方法创建独立的Camel上下文(未手动开启上下文缓存的前提下),只要在context.start()调用前设置过滤规则,配置就只会作用于当前测试方法:
@Test void testOnlyTranslationRoute() throws Exception { // 上下文启动前设置包含规则,仅匹配目标路由ID context.setRouteFilterPattern("my-translation-route", null); AdviceWith.adviceWith(context, "my-translation-route", a -> { a.mockEndpointsAndSkip("direct:my-outbound-route"); }); context.start(); // 后续测试逻辑和原有逻辑一致 }
内容的提问来源于stack exchange,提问作者Bart Weber

