Тестирование весенних загрузок Apache Camel Routes
У меня есть приложение Springboot, в котором настроены верблюжьи маршруты.
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 всегда нулевой. Я попробовал Autowiring Camelcontext, для которого я получил исключение, сказав, что он не может разрешить camelContext. Но это можно решить, добавив SpringCamelContext.class в классы @SpringBootTest. Но мой ProducerTemplate все еще нулевой.
пожалуйста, предложите. Я использую Camel 2.18 Springboot 1.4
3 ответа
Вот как я это сделал наконец
@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 a 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();
}
}
В Camel 2.22.0 и более поздних версиях, поддерживающих Spring Boot 2, вы можете использовать следующий шаблон для проверки ваших маршрутов с поддержкой Spring Boot 2:
@RunWith(SpringRunner.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 сделает это за вас.
Для одного маршрута с 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.
Вы пробовали использовать тестер Camel?
@RunWith(CamelSpringJUnit4ClassRunner.class)
Если вы используете camel-spring-boot
зависимость, вы можете знать, что он использует автоматическую настройку для настройки Camel:
CamelAutoConfiguration.java
Это означает, что вам также может понадобиться добавить @EnableAutoConfiguration
к вашему тесту.