Spring 启动 Apache Camel 路由测试

Spring Boot Apache Camel Routes testing

我有一个 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.

您尝试过使用 Camel 测试运行程序吗?

@RunWith(CamelSpringJUnit4ClassRunner.class)

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

CamelAutoConfiguration.java

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

这就是我最终做到的:

    @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();
        }
    }

在支持 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。如果在顶层 class 上注释,则入门级将替换任何现有配置,而 @TestConfiguration 除了其他配置外,将是 运行。

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

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

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

对于带有 MQ 和 Spring 的一条路由,像这样引导:

    @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.

上提供了完整的源代码