【问题标题】:Spring Boot Apache Camel Routes testingSpring Boot Apache Camel 路由测试
【发布时间】:2017-07-05 16:04:01
【问题描述】:

我有一个 Springboot 应用程序,其中配置了一些 Camel 路由。

public class CamelConfig {
    private static final Logger LOG = LoggerFactory.getLogger(CamelConfig.class);

    @Value("${activemq.broker.url:tcp://localhost:61616}")
    String brokerUrl;

    @Value("${activemq.broker.maxconnections:1}")
    int maxConnections;

    @Bean
    ConnectionFactory jmsConnectionFactory() {
        PooledConnectionFactory pooledConnectionFactory = new PooledConnectionFactory(new ActiveMQConnectionFactory(brokerUrl));
        pooledConnectionFactory.setMaxConnections(maxConnections);
        return pooledConnectionFactory;
    }

    @Bean
    public RoutesBuilder route() {
        LOG.info("Initializing camel routes......................");
        return new SpringRouteBuilder() {
            @Override
            public void configure() throws Exception {
                from("activemq:testQueue")
                  .to("bean:queueEventHandler?method=handleQueueEvent");
            }
        };
    }
}

我想测试从activemq:testQueuequeueEventHandler::handleQueueEvent 的这条路线。 我尝试了http://camel.apache.org/camel-test.html 此处提到的不同方法,但似乎无法正常工作。

我正在尝试做这样的事情:

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = {CamelConfig.class,   CamelTestContextBootstrapper.class})
    public class CamelRouteConfigTest {

    @Produce(uri = "activemq:testQueue")
    protected ProducerTemplate template;

    @Test
    public void testSendMatchingMessage() throws Exception {
        template.sendBodyAndHeader("testJson", "foo", "bar");
        // Verify handleQueueEvent(...) method is called on bean queueEventHandler by mocking
    }

但我的 ProducerTemplate 始终是 null。我尝试了自动连线CamelContext,但我得到一个异常提示它无法解析camelContext。但这可以通过将SpringCamelContext.class 添加到@SpringBootTest 类来解决。但我的ProducerTemplate 仍然是null

请提出建议。我正在使用 Camel 2.18 和 Spring Boot 1.4。

【问题讨论】:

    标签: spring-boot apache-camel camel-test


    【解决方案1】:

    这就是我最终的做法:

        @RunWith(SpringRunner.class)
        public class CamelRouteConfigTest extends CamelTestSupport {
        
            private static final Logger LOG = LoggerFactory.getLogger(CamelRouteConfigTest.class);
            private static BrokerService brokerSvc = new BrokerService();
        
            @Mock
            private QueueEventHandler queueEventHandler;
        
            @BeforeClass
            // Sets up an embedded broker
            public static void setUpBroker() throws Exception {
                brokerSvc.setBrokerName("TestBroker");
                brokerSvc.addConnector("tcp://localhost:61616");
                brokerSvc.setPersistent(false);
                brokerSvc.setUseJmx(false);
                brokerSvc.start();
            }
        
            @Override
            protected RoutesBuilder createRouteBuilder() throws Exception {
                return new CamelConfig().route();
            }
        
            // properties in .yml has to be loaded manually. Not sure of .properties file
            @Override
            protected Properties useOverridePropertiesWithPropertiesComponent() {
                YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
                try {
                    PropertySource<?> applicationYamlPropertySource = loader.load(
                        "properties", new ClassPathResource("application.yml"),null);// null indicated common properties for all profiles.
                    Map source = ((MapPropertySource) applicationYamlPropertySource).getSource();
                    Properties properties = new Properties();
                    properties.putAll(source);
                    return properties;
                } catch (IOException e) {
                    LOG.error("application.yml file cannot be found.");
                }
        
                return null;
            }
        
            @Override
            protected JndiRegistry createRegistry() throws Exception {
                JndiRegistry jndi = super.createRegistry();
                MockitoAnnotations.initMocks(this);
                jndi.bind("queueEventHandler", queueEventHandler);
        
                return jndi;
            }
        
            @Test
            // Sleeping for a few seconds is necessary, because this line template.sendBody runs in a different thread and
            // CamelTest takes a few seconds to do the routing.
            public void testRoute() throws InterruptedException {
                template.sendBody("activemq:productpushevent", "HelloWorld!");
                Thread.sleep(2000);
                verify(queueEventHandler, times(1)).handleQueueEvent(any());
            }
        
            @AfterClass
            public static void shutDownBroker() throws Exception {
                brokerSvc.stop();
            }
        }
    

    【讨论】:

    • 能否在 Git 中提供完整的路由和测试代码?谢谢。
    • @pvpkiran,首先感谢您的分享。 template 来自哪里?我正在为此苦苦挣扎。
    • @ddsultan 模板通过 CamelTestSupport 类解析(因为 CamelRouteConfigTest 扩展了 CamelTestSupport)
    • @gurpal2000,谢谢,我会检查的。
    【解决方案2】:

    对于一个使用 MQ 和 Spring Boot 的路由,如下所示:

        @Component
        public class InboundRoute extends RouteBuilder {
        
          @Override
          public void configure() {
            JaxbDataFormat personDataFormat = new JaxbDataFormat();
            personDataFormat.setContextPath(Person.class.getPackage().getName());
            personDataFormat.setPrettyPrint(true);
            from("direct:start").id("InboundRoute")
                .log("inbound route")
                .marshal(personDataFormat)
                .to("log:com.company.app?showAll=true&multiline=true")
                .convertBodyTo(String.class)
                .inOnly("mq:q.empi.deim.in")
                .transform(constant("DONE"));
          }
        }
    

    我使用adviceWith 来替换端点并且只使用模拟:

        @RunWith(CamelSpringBootRunner.class)
        @UseAdviceWith
        @SpringBootTest(classes = InboundApp.class)
        @MockEndpoints("mock:a")
        public class InboundRouteCamelTest {
        
          @EndpointInject(uri = "mock:a")
          private MockEndpoint mock;
        
          @Produce(uri = "direct:start")
          private ProducerTemplate template;
        
          @Autowired
          private CamelContext context;
        
          @Test
          public void whenInboundRouteIsCalled_thenSuccess() throws Exception {
            mock.expectedMinimumMessageCount(1);
            RouteDefinition route = context.getRouteDefinition("InboundRoute");
            route.adviceWith(context, new AdviceWithRouteBuilder() {
              @Override
              public void configure() {
                weaveByToUri("mq:q.empi.deim.in").replace().to("mock:a");
              }
            });
            context.start();
        
            String response = (String) template.requestBodyAndHeader("direct:start",
                getSampleMessage("/SimplePatient.xml"), Exchange.CONTENT_TYPE, MediaType.APPLICATION_XML);
        
            assertThat(response).isEqualTo("DONE");
            mock.assertIsSatisfied();
          }
        
          private String getSampleMessage(String filename) throws Exception {
            return IOUtils
                .toString(this.getClass().getResourceAsStream(filename), StandardCharsets.UTF_8.name());
          }
        }
    

    我使用以下依赖项:Spring Boot 2.1.4-RELEASE 和 Camel 2.23.2。完整的源代码在Github

    【讨论】:

      【解决方案3】:

      在支持 Spring Boot 2 的 Camel 2.22.0 和正在进行中,您可以使用以下模板来测试您的路由是否支持 Spring Boot 2:

      @RunWith(CamelSpringRunner.class)
      @SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = {
          Route1.class,
          Route2.class,
          ...
      })
      @EnableAutoConfiguration
      @DisableJmx
      @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
      public class RouteTest {
      
        @TestConfiguration
        static class Config {
          @Bean
          CamelContextConfiguration contextConfiguration() {
            return new CamelContextConfiguration() {
              @Override
              public void beforeApplicationStart(CamelContext camelContext) {
                // configure Camel here
              }
      
              @Override
              public void afterApplicationStart(CamelContext camelContext) {
                // Start your manual routes here
              }
            };
          }
      
          @Bean
          RouteBuilder routeBuilder() {
            return new RouteBuilder() {
              @Override
              public void configure() {
                from("direct:someEndpoint").to("mock:done");
              }
            };
          }
      
          // further beans ...
        }
      
        @Produce(uri = "direct:start")
        private ProducerTemplate template;
        @EndpointInject(uri = "mock:done")
        private MockEndpoint mockDone;
      
        @Test
        public void testCamelRoute() throws Exception {
          mockDone.expectedMessageCount(1);
      
          Map<String, Object> headers = new HashMap<>();
          ...
          template.sendBodyAndHeaders("test", headers);
      
          mockDone.assertIsSatisfied();
        }
      }
      

      Spring Boot 区分 @Configuration@TestConfiguration。如果在顶级类上注释,则入门级将替换任何现有配置,而 @TestConfiguration 将在其他配置之外运行。

      此外,在较大的项目中,您可能会遇到自动配置问题,因为您不能依赖 Spring Boot 2 来配置您的自定义数据库池或不正确的情况,或者在您具有特定目录结构且配置为不位于直接祖先目录中。在这种情况下,最好省略@EnableAutoConfiguration 注释。为了告诉 Spring 仍然自动配置 Camel,您可以简单地将 CamelAutoConfiguration.class 传递给 @SpringBootTest 中提到的类

      @SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = {
          Route1.class,
          Route2.class,
          RouteTest.Config.class,
          CamelAutoConfiguration.class
      }
      

      由于没有执行自动配置,Spring 不会在您的测试类中加载测试配置,也不会初始化 Camel。通过手动将这些配置添加到引导类中,Spring 将为您完成。

      【讨论】:

      • @DisableJmx 不会禁用 JMX,因为测试被标记为使用 SpringRunner 运行,而不是 CamelSpringRunner
      • @realmfoo 感谢您的提示。我正在更新帖子
      • 您知道如何在此设置中使用属性吗?我在这里查看他们的页面:camel.apache.org/manual/latest/…,他们引用了 UseOverridePropertiesWithPropertiesComponent ?
      • @RyuS。您是否尝试将 @PropertySource("classpath:some.properties") 添加到您的配置类?
      • @RyuS。另外,this thread here 你可能会感兴趣
      【解决方案4】:

      您是否尝试过使用 Camel 测试运行器?

      @RunWith(CamelSpringJUnit4ClassRunner.class)
      

      如果你使用 camel-spring-boot 依赖,你可能知道它使用自动配置来设置 Camel:

      CamelAutoConfiguration.java
      

      这意味着您可能还需要将@EnableAutoConfiguration 添加到您的测试中。

      【讨论】:

      • 嗨,CamelSpringJUnit4ClassRunner 已被弃用。我让它与这样的东西一起工作。 public class AmqTest extends CamelTestSupport { @Override protected RoutesBuilder createRouteBuilder() throws Exception { return new ActiveMqConfig().route(); }
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-01
      • 1970-01-01
      • 2018-01-17
      • 2021-04-30
      • 2020-03-07
      相关资源
      最近更新 更多