编写Apache Camel路由测试用例时断言失败问题求助
Apache Camel测试断言失败与AdviceWith报错解决方案
问题概述
- 测试断言失败:期望
mock://seda:processMessage?blockWhenFull=true收到1条消息,但实际为0,调试确认消息能正常流转 - 直接修改路由添加
mock:前缀可让测试生效,但希望不改动路由实现 - 使用AdviceWith时触发错误:
Cannot advice routes as there are no routes
原因分析
1. @MockEndpoints断言失败原因
路由中使用了parallelProcessing()和自定义线程池,消息在异步线程中处理,测试主线程在异步线程完成前就执行了mock.assertIsSatisfied(),导致断言时消息尚未到达mock端点。
2. AdviceWith报错原因
调用AdviceWith时传入的是目标端点地址(Endpoints.SEDA_PROCESS_ENDPOINT),但AdviceWith需要指定路由ID;同时没有在Camel上下文启动前执行AdviceWith,路由初始化完成后无法修改。
解决方案
方案一:修复@MockEndpoints的异步处理问题
无需修改路由,仅调整测试逻辑,给异步线程足够的处理时间:
@Test void test() throws Exception { mock.expectedBodiesReceived(costIQPayloadString()); // 设置超时时间(如10秒),确保异步线程完成消息处理 mock.setResultWaitTime(10000); // 改用任意参数匹配,避免对象equals不匹配导致mock失效 Mockito.when(rulesEngineClientMock.validateRules(Mockito.any(CostIQRetail.class))) .thenReturn(costIQObject()); Map<String, Object> headers = new HashMap<>(); headers.put("appName", "costIQ"); template.sendBodyAndHeaders(Endpoints.SEDA_SEND_ENDPOINT, costIQObject(), headers); mock.assertIsSatisfied(); }
方案二:正确使用AdviceWith修改路由
在Camel上下文启动前执行AdviceWith,且指定路由ID而非端点地址:
@SpringBootTest @CamelSpringBootTest public class CamelRouteTests3 { @Autowired private ProducerTemplate template; @Autowired private CamelContext context; private MockEndpoint mock; @Mock private RulesEngineClient rulesEngineClientMock; // 在测试初始化阶段执行AdviceWith,确保路由启动前完成修改 @BeforeEach void setup() throws Exception { // 针对路由ID为Endpoints.SEDA_SEND_ENDPOINT的路由进行修改 AdviceWith.adviceWith(context, Endpoints.SEDA_SEND_ENDPOINT, a -> { // 自动将所有发送到Endpoints.SEDA_PROCESS_ENDPOINT的请求转发到mock端点 a.mockEndpoints(Endpoints.SEDA_PROCESS_ENDPOINT); }); // 获取自动生成的mock端点 mock = context.getEndpoint("mock:" + Endpoints.SEDA_PROCESS_ENDPOINT, MockEndpoint.class); } // 测试方法逻辑同方案一... @Test void test() throws Exception { mock.expectedBodiesReceived(costIQPayloadString()); mock.setResultWaitTime(10000); Mockito.when(rulesEngineClientMock.validateRules(Mockito.any(CostIQRetail.class))) .thenReturn(costIQObject()); Map<String, Object> headers = new HashMap<>(); headers.put("appName", "costIQ"); template.sendBodyAndHeaders(Endpoints.SEDA_SEND_ENDPOINT, costIQObject(), headers); mock.assertIsSatisfied(); } }
额外优化建议
- 测试时可通过AdviceWith关闭并行处理,彻底避免异步问题:
a.replaceFromWith(Endpoints.SEDA_SEND_ENDPOINT).removeMulticastParallelProcessing(); - 确保
CostIQRetail类的equals方法实现正确,避免参数匹配和断言失败
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

