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:testQueue
到 queueEventHandler::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.
上提供了完整的源代码
我有一个 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:testQueue
到 queueEventHandler::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
@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.
上提供了完整的源代码