Camel/Quarkus中AdviceWith无法按ID找到路由的测试问题
Camel路由测试问题解决指南
定义的Camel路由
from("direct:someRoute") .id("someRoute") .log(...) .to("sql-stored:someProcedure(BIGINT ${exchangeProperty.someVal})") .id("someCall") .log(...) .end()
测试代码(Quarkus环境)
@QuarkusTest public class Tests{ @Inject CamelContext camelContext; @BeforeEach public void setup(){ AdviceWith.adviceWith( this.camelContext, "someRoute", a -> { a.weaveById("someCall") .replace() .setBody() .constant("{}"); } ); } @Test public void testOne(){ //... } @Test public void testTwo(){ //... } }
出现的错误
- 第一个测试报错:
Cannot advice route as route with id: someRoute does not exists
- 第二个测试报错:
There are no outputs with matches: someCall in the route: <routeToString, oddly with no mention of the someCall route, or even an sql route>
日志显示路由已加载,但路由的toString结果中未提及someCall节点。
问题排查过程
- 推测问题与
@BeforeEach注解有关,尝试确定是否应该只执行一次AdviceWith,或重置Camel上下文后重新应用Mock。 - 尝试调用
context.stop()和context.start()但不支持;改用CamelQuarkusTestSupport后第一个测试正常,但后续测试的Camel上下文为空,无任何路由。
解决方案
方案1:控制AdviceWith执行时机与路由状态
Quarkus启动时会提前初始化Camel上下文并加载路由,@BeforeEach在每个测试前执行会导致两次问题:第一次执行时路由可能未完全初始化,第二次执行时someCall节点已被替换消失。
将AdviceWith移至@BeforeAll(仅执行一次),并在修改前暂停路由、修改后启动:
@QuarkusTest public class Tests{ @Inject CamelContext camelContext; @BeforeAll public void setup() throws Exception { // 暂停目标路由,确保修改时路由未启动 RouteDefinition route = camelContext.getRouteDefinition("someRoute"); route.stop(); AdviceWith.adviceWith( camelContext, "someRoute", a -> { a.weaveById("someCall") .replace() .setBody() .constant("{}"); } ); // 修改完成后启动路由 route.start(); } @Test public void testOne(){ //... } @Test public void testTwo(){ //... } }
方案2:启用测试上下文隔离
如果需要每个测试用例都使用全新的Camel上下文,可通过@TestInstance或@ResetTestState实现(Quarkus 2.7+支持@ResetTestState):
@QuarkusTest @TestInstance(TestInstance.Lifecycle.PER_METHOD) // 每个测试方法重新初始化实例 public class Tests{ @Inject CamelContext camelContext; @BeforeEach public void setup() throws Exception { AdviceWith.adviceWith( camelContext, "someRoute", a -> { a.weaveById("someCall") .replace() .setBody() .constant("{}"); } ); } // 测试方法... }
方案3:使用MockEndpoint替代AdviceWith
无需修改路由结构,直接拦截并模拟存储过程端点的返回值:
@QuarkusTest public class Tests{ @Inject CamelContext camelContext; @BeforeEach public void setup() throws Exception { // 替换原SQL存储过程端点为Mock端点 String originalUri = "sql-stored:someProcedure(BIGINT ${exchangeProperty.someVal})"; MockEndpoint mockEndpoint = camelContext.getEndpoint("mock:someProcedure", MockEndpoint.class); mockEndpoint.returnReplyBody(constant("{}")); // 动态替换端点 camelContext.getRouteDefinition("someRoute") .adviceWith(camelContext, a -> a.weaveByToUri(originalUri).replace().to("mock:someProcedure")); } @Test public void testOne(){ //... } }
内容的提问来源于stack exchange,提问作者Snappawapa
相关产品推荐
相关产品推荐

