[英]Spring Boot Apache Camel Routes testing
I have a Springboot application, where I have some Camel routes configured.我有一个 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");
}
};
}
}
I want to test this route from activemq:testQueue
to queueEventHandler::handleQueueEvent
.我想测试从activemq:testQueue
到queueEventHandler::handleQueueEvent
这条路线。 I tried different things mentioned here http://camel.apache.org/camel-test.html , but doesn't seem to get it working.我尝试了这里提到的不同内容http://camel.apache.org/camel-test.html ,但似乎没有让它工作。
I am trying to do something like this:我正在尝试做这样的事情:
@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
}
But my ProducerTemplate is always null
.但我的 ProducerTemplate 始终为null
。 I tried auto-wiring CamelContext
, for which I get an exception saying it cannot resolve camelContext .我尝试自动连接CamelContext
,为此我收到一个异常,说它无法解析 camelContext 。 But that can be resolved by adding SpringCamelContext.class
to @SpringBootTest
classes.但这可以通过将SpringCamelContext.class
添加到@SpringBootTest
类来解决。 But my ProducerTemplate
is still null
.但是我的ProducerTemplate
仍然是null
。
Please suggest.请建议。 I am using Camel 2.18 and Spring Boot 1.4.我正在使用 Camel 2.18 和 Spring Boot 1.4。
In Camel 2.22.0 and ongoing, which supports Spring Boot 2 you can use the following template to test your routes with Spring Boot 2 support:在支持 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 distinguishes between @Configuration
and @TestConfiguration
. Spring Boot 区分@Configuration
和@TestConfiguration
。 The primer one will replace any existing configuration, if annotated on a top-level class, while @TestConfiguration
will be run in addition to the other configurations.如果在顶级类上注释,则初级将替换任何现有配置,而@TestConfiguration
将在其他配置之外运行。
Further, in larger projects you might run into auto-configuration issues as you can't rely on Spring Boot 2 to configure your custom database pooling or what not correctly or in cases where you have a specific directory structure and the configurations are not located within a direct ancestor directory.此外,在较大的项目中,您可能会遇到自动配置问题,因为您不能依赖 Spring Boot 2 来配置自定义数据库池或不正确的配置,或者在您具有特定目录结构且配置不在其中的情况下直接祖先目录。 In that case it is proabably preferable to omit the @EnableAutoConfiguration
annotation.在这种情况下,省略@EnableAutoConfiguration
注释可能更可取。 In order to tell Spring to still auto-configure Camel you can simply pass CamelAutoConfiguration.class
to the classes mentioned in @SpringBootTest
为了告诉Spring还是自动配置骆驼,你可以简单地传递CamelAutoConfiguration.class
中提到的类@SpringBootTest
@SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = {
Route1.class,
Route2.class,
RouteTest.Config.class,
CamelAutoConfiguration.class
}
As no automatic configuration is performed, Spring won't load the test configuration inside your test class nor initialize Camel as well.由于没有执行自动配置,Spring 不会在您的测试类中加载测试配置,也不会初始化 Camel。 By adding those configs to the boot classes manually Spring will do it for you.通过手动将这些配置添加到引导类,Spring 将为您完成。
For one route with MQ and Spring Boot like this:对于一个带有 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"));
}
}
I use adviceWith in order to replace the endpoint and use only mocks:我使用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());
}
}
I use the following dependencies: Spring Boot 2.1.4-RELEASE and Camel 2.23.2.我使用以下依赖项:Spring Boot 2.1.4-RELEASE 和 Camel 2.23.2。 The complete source code is available on Github .完整的源代码可在Github 上获得。
This is how I did this finally:这就是我最终这样做的方式:
@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();
}
}
Did you try using Camel test runner?您是否尝试过使用 Camel 测试运行器?
@RunWith(CamelSpringJUnit4ClassRunner.class)
If you are using camel-spring-boot
dependency, you may know that it uses auto configuration to setup Camel:如果你使用camel-spring-boot
依赖,你可能知道它使用自动配置来设置Camel:
CamelAutoConfiguration.java
It means that you may also need to add @EnableAutoConfiguration
to your test.这意味着您可能还需要将@EnableAutoConfiguration
添加到您的测试中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.