You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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节点。

问题排查过程

  1. 推测问题与@BeforeEach注解有关,尝试确定是否应该只执行一次AdviceWith,或重置Camel上下文后重新应用Mock。
  2. 尝试调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:07:08