Spring boot integration testing Jersey JAX-RS resource - spring-boot

I am using Spring Boot 2.0.3.RELEASE and creating a simple Jersey JAX-RS resource (using the jersey spring boot starter). I would like to do a simple integration test using a Jersey Client class I have written, it doesn't seem however that the resource has started as I get a java.net.ConnectException: Connection refused
So here we go, first the simple resource
#Component
#Path(Constants.STATUS_PATH)
public class StatusResource {
private static final String OK = "OK";
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response getStatus() {
return Response.ok(OK).build();
}
}
The Jersey config
#Component
public class JerseyConfig extends ResourceConfig {
private static final Logger logger = LoggerFactory.getLogger(JerseyConfig.class);
public JerseyConfig() {
logger.debug("Registering JAX-RS resources");
register(StatusResource.class);
}
}
The Spring boot application class
#SpringBootApplication
public class Application {
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
logger.info("==== Starting Services ====");
SpringApplication.run(Application.class, args);
}
}
The Jersey Client
public class ServicesClient {
private static final Logger logger = LoggerFactory.getLogger(ServicesClient.class);
private Client client;
public ServicesClient() {
client = initJerseyClient();
}
private Client initJerseyClient() {
logger.debug("Initialising Jersey Client");
ClientConfig jerseyClientConfig = new ClientConfig();
return ClientBuilder.newClient(jerseyClientConfig);
}
/**
* Returns OK if services are running
*
* #return service status
*/
public String getServicesStatus() {
logger.debug("Client get services status request");
Response respone = client.target("http://localhost:8080").path(Constants.STATUS_PATH).request().get();
return respone.readEntity(String.class);
}
}
And finally the Spring Boot integration test
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes = Application.class)
public class StatusResourceTest {
private static Logger logger = LoggerFactory.getLogger(StatusResourceTest.class);
private static ServicesClient servicesClient;
#BeforeAll
public static void setup() throws IOException {
logger.debug("--- Starting StatusResourceTest setup ---");
System.setProperty("services.client.file", "classpath:com/zurich/utils/services/config/services.yaml");
servicesClient = new ServicesClientBuilder().build();
}
#Test
public void testGetStatus() {
logger.debug("--- Starting testGetStatus ---");
String status = servicesClient.getServicesStatus();
assertThat("Service status should be OK", status, equalTo("OK"));
}
}
Like I said when the test runs and get is called inside the client, I get the following stack trace. Which to me implies the resource isn't running at http://localhost:8080 but I don't know why.
javax.ws.rs.ProcessingException: java.net.ConnectException: Connection refused: connect
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:284)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:278)
at org.glassfish.jersey.client.JerseyInvocation.lambda$invoke$0(JerseyInvocation.java:753)
at org.glassfish.jersey.internal.Errors.process(Errors.java:316)
at org.glassfish.jersey.internal.Errors.process(Errors.java:298)
at org.glassfish.jersey.internal.Errors.process(Errors.java:229)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:414)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:752)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:419)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:319)
at com.xxx.utils.services.client.ServicesClient.getServicesStatus(ServicesClient.java:178)
at sit.resource.status.StatusResourceTest.testGetStatus(StatusResourceTest.java:39)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:390)
at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:282)
... 11 more

It appears the issue was with the #SpringBootTest annotation, I changed it to the following and it is now working
#SpringBootTest(classes = Application.class, webEnvironment = WebEnvironment.DEFINED_PORT)

Related

Cannot connect to rabbitmq STOMP from Spring boot

I have used the RabbitMQ docker image which has STOMP enabled. With the following configuration, when I try to run my Spring Boot Application, I am getting an exception.
StackTrace:
2020-11-21 16:03:07.620 INFO 28504 --- [ient-loop-nio-1] o.s.m.s.s.StompBrokerRelayMessageHandler : TCP connection failure in session system: Failed to connect: Connection refused: /127.0.0.1:61613
io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:61613
Caused by: java.net.ConnectException: Connection refused
at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) ~[na:1.8.0_242]
at sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:714) ~[na:1.8.0_242]
at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:330) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:334) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:702) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.51.Final.jar:4.1.51.Final]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_242]
Dockerfile
FROM rabbitmq:3-management
RUN rabbitmq-plugins enable --offline rabbitmq_stomp
EXPOSE 61613
The logs from Rabbitmq container looks fine to me.
WebSocketConfig.java looks like:
#EnableWebSocketMessageBroker
#Configuration
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-connection")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/topic", "/queue")
.setRelayPort(61613)
.setRelayHost("127.0.0.1")
.setClientPasscode("guest")
.setClientLogin("guest");
registry.setApplicationDestinationPrefixes("/ws");
}
}
pom.xml
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
What's wrong with the configuration? Can anyone help me?
I think you made a mistake while exposing the rabbitmq stomp port 61613 for the client. By the way, I tested with a similar configuration it works for me.
For implementation please check my demo application on GitHub or read the following details.
Dockerfile
FROM rabbitmq:3-management
RUN rabbitmq-plugins enable --offline rabbitmq_stomp
EXPOSE 15671 15672 61613
Server Implementation
Message Contract
public class ZbytesMessage {
private String from;
private String text;
...getters and setters...
}
WebSocket Configuration
#Configuration
#EnableWebSocketMessageBroker
public class StompConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/zsockets")
.setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableStompBrokerRelay("/topic", "/queue")
.setRelayHost("localhost")
.setRelayPort(61613)
.setClientLogin("guest")
.setClientPasscode("guest");
config.setApplicationDestinationPrefixes("/zbytes");
}
}
Web Controller
#Controller
public class ZbytesController {
private static final Logger LOG = LoggerFactory.getLogger(ZbytesController.class);
#MessageMapping("/hello")
#SendTo("/topic/greetings")
public ZbytesMessage greeting(ZbytesMessage msg) throws Exception {
Thread.sleep(1000); // simulated delay
LOG.info("Received : {} from: {} ", msg.getText(), msg.getFrom());
return msg;
}
}
Server Runner
#SpringBootApplication
public class ServerRunner {
public static void main(String[] args) {
SpringApplication.run(ServerRunner.class, args);
}
}
Client Implementation
public class HelloClient {
private static final WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
private static final Logger LOG = LoggerFactory.getLogger(HelloClient.class);
public static void main(String[] args) throws Exception {
HelloClient helloClient = new HelloClient();
ListenableFuture<StompSession> f = helloClient.connect();
StompSession stompSession = f.get();
LOG.info("Subscribing to greeting topic using session {}", stompSession);
helloClient.subscribeGreetings(stompSession);
LOG.info("Sending hello message {}", stompSession);
helloClient.sendHello(stompSession);
Thread.sleep(60000);
}
public ListenableFuture<StompSession> connect() {
Transport webSocketTransport = new WebSocketTransport(new StandardWebSocketClient());
List<Transport> transports = Collections.singletonList(webSocketTransport);
SockJsClient sockJsClient = new SockJsClient(transports);
sockJsClient.setMessageCodec(new Jackson2SockJsMessageCodec());
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
String url = "ws://{host}:{port}/zsockets";
return stompClient.connect(url, headers, new MyHandler(), "localhost", 8080);
}
public void subscribeGreetings(StompSession stompSession) {
stompSession.subscribe("/topic/greetings", new StompFrameHandler() {
public Type getPayloadType(StompHeaders stompHeaders) {
return byte[].class;
}
public void handleFrame(StompHeaders stompHeaders, Object o) {
LOG.info("Received greeting {}", new String((byte[]) o));
}
});
}
public void sendHello(StompSession stompSession) {
String jsonHello = "{ \"from\" : \"suraj\", \"text\" : \"Hi zbytes!\" }";
stompSession.send("/zbytes/hello", jsonHello.getBytes());
}
private static class MyHandler extends StompSessionHandlerAdapter {
#Override
public void afterConnected(StompSession stompSession, StompHeaders stompHeaders) {
LOG.info("Now connected");
}
}
}
To Run
Build the docker image and run it (don't forget to expose port 61613). (Note: I would prefer docker-compose.yaml)
docker build -t zbytes/rabbitmq .
docker run -p61613:61613 zbytes/rabbitmq
Run ServerRunner java main class.
Run HelloClient java main class.
Server Output
i.g.zbytes.demo.server.ZbytesController : Received : Hi zbytes! from: suraj
Client Output
Received greeting {"from":"suraj","text":"Hi zbytes!"}

Spring Boot testing with Junit

Using Spring Boot 2.0.3.RELEASE
The goal of the test is have a service call a controller in the same app.
Here is the simplified setup I am trying
The app class
#SpringBootApplication
public class StartApp {
public static void main(String[] args) {
SpringApplication.run(StartApp.class, args);
}
}
The controller class
#RestController
public class EmpCtrl {
private static final Logger logger = LoggerFactory.getLogger(EmpCtrl.class);
#Autowired
private EmpDao empDao;
#RequestMapping(value = "/emp01", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public List<Emp> findAllEmp01() {
logger.trace("running my.demo.controller.findAllEmp01");
List<Emp> emps = new ArrayList<>();
Iterable<Emp> results = this.empDao.findAll();
results.forEach(emp -> {emps.add(emp);});
return emps;
}
}
The service class
#Service
public class GetEmpSrv {
private static final Logger logger = LoggerFactory.getLogger(GetEmpSrv.class);
public void getEmps01(){
final String uri = "http://localhost:8080/emp01";
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri, String.class);
logger.debug(result);
}
}
and the Junit class
#RunWith(SpringRunner.class)
#SpringBootTest(classes = StartApp.class)
public class GetEmpSrvTest01 {
#Test
public void doCall() {
GetEmpSrv getEmpSrv = new GetEmpSrv();
getEmpSrv.getEmps01();
}
}
This is being run inside Eclipse Oxygen.3a (4.7.3a)
in the console it appears Spring Boot is running .. ic the load of h2 db and /emp01 is being mapped however in the Failure Trace of Junit ic
I/O error on GET request for "http://localhost:8080/emp01": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
This makes me think the embedded Tomcat is not running. When I start Spring normally /emp01 returns a JSON as expected.
My question is: Is this type of testing possible with Junit? If so what do I need to do to make it work?
In your test, please autowire TestRestTemplate. The reason is that your spring test will run on another port and the call to http://localhost:8080 will fail.
#RunWith(SpringRunner.class)
#SpringBootTest(classes = StartApp.class)
public class GetEmpSrvTest01 {
#Autowired
TestRestTemplate testRestTemplate;
#Test
public void doCall() {
// without http://localhost:8080, testRestTemplate it will handle it for you
testRestTemplate.getForObject("/emp01", String.class);
}
}
Also you can expect a list of objects in your test:
List<Emp> emps = testRestTemplate.getForObject("/emp01", List.class);

SpringBoot reads all properties as 0

Using SpringBoot, I'm having simple class
#Component
#PropertySource("server.properties")
public class CoreFacade {
private static final Logger log = Logger.getLogger(CoreFacade.class);
#Value("${chat.server.port}")
private int port;
private Server server;
public CoreFacade() {
log.info(String.valueOf(port));
server = new Server(port);
}
}
and under src/main/resources I got server.properties with
chat.server.port = 9999
Yet logging this ends up with
INFO 2018-08-20 21:48:02,878 [main]
com.example.chatserver.core.CoreFacade [] [] - 0
instead of 9999
Any ideas what could possibly go wrong here?
You annotated your class as a Spring component.
It prints 0 as the constructor is invoked by Spring before any dependency injection done for the bean.
What you need is to declaring the class as a configuration class such as :
#Configuration
#PropertySource("server.properties")
public class CoreFacade {
...
}
If it makes sense you could make Server a bean defined in the class such as :
#Value("${chat.server.port}")
private int port;
#Bean
public Server server() {
return new Server(port);
}
An alternative solution as the one proposed by davidxxx, is to mark your constructor as #Autowired :
#Component
#PropertySource("server.properties")
public class CoreFacade {
private static final Logger log = Logger.getLogger(CoreFacade.class);
private Server server;
#Autowired
public CoreFacade(
#Value("${chat.server.port}")
int port
) {
log.info(String.valueOf(port));
server = new Server(port);
}
}
You could also use #PostConstruct, which is called after #Value resolution :
#Component
#PropertySource("server.properties")
public class CoreFacade {
private static final Logger log = Logger.getLogger(CoreFacade.class);
#Value("${chat.server.port}")
private int port;
private Server server;
#PostConstruct
public void postConstruct() {
log.info(String.valueOf(port));
server = new Server(port);
}
}

Spring Boot Apache Camel Routes testing

I have a Springboot application, where I have some Camel routes configured.
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.
I tried different things mentioned here http://camel.apache.org/camel-test.html, but doesn't seem to get it working.
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. I tried auto-wiring CamelContext, for which I get an exception saying it cannot resolve camelContext. But that can be resolved by adding SpringCamelContext.class to #SpringBootTest classes. But my ProducerTemplate is still null.
Please suggest. I am using Camel 2.18 and 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:
#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. 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.
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. In that case it is proabably preferable to omit the #EnableAutoConfiguration annotation. In order to tell Spring to still auto-configure Camel you can simply pass CamelAutoConfiguration.class to the classes mentioned in #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. By adding those configs to the boot classes manually Spring will do it for you.
For one route with MQ and Spring Boot like this:
#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:
#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. The complete source code is available on 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?
#RunWith(CamelSpringJUnit4ClassRunner.class)
If you are using camel-spring-boot dependency, you may know that it uses auto configuration to setup Camel:
CamelAutoConfiguration.java
It means that you may also need to add #EnableAutoConfiguration to your test.

Camel Spring Boot MockEndpoint assertion not working as expected

My test application can start up normally with CamelSpringBootApplicationController. However, when I am working on the integration test, the assertion of MockEndpoint is not working as expected The snapshot of my test code is listed below. Am I doing anything wrong?
Application.java
#SpringBootApplication
public class Application {
....
public static final String DIRECT_BT_INPUT = "direct:btInput";
public static final String DIRECT_BT_OUTPUT = "direct:btOutput";
#Bean
public RouteBuilder RouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from(DIRECT_BT_INPUT).log("${body}").to(DIRECT_BT_OUTPUT);
from(DIRECT_BT_OUTPUT).log("done");
}
};
}
}
BTRouteUnitTest.java
#RunWith(CamelSpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
#MockEndpoints(Application.DIRECT_BT_OUTPUT)
public class BTRouteIT {
#Autowired
protected CamelContext camelContext;
#EndpointInject(uri = "mock:" + Application.DIRECT_BT_OUTPUT)
protected MockEndpoint mockBtOutput;
#Produce(uri = Application.DIRECT_BT_INPUT)
protected ProducerTemplate producerTemplate;
#Test
public void test() throws InterruptedException {
mockBtOutput.expectedBodiesReceived("Hello");
producerTemplate.sendBody("Hello");
MockEndpoint.assertIsSatisfied(camelContext);
}
}
#MockEndpoint is not supported yet in Camel Spring Boot.
Workaround: move endpoint uris to properties file (in route definition use {{}}) and use different property file where you substitute original endpoint uri with mock:orginalUri.
You are testing with CamelSpringJUnit4ClassRunner in camel-test-spring. Camel spring test is for regular spring, not spring-boot.
Use SpringJUnit4ClassRunner test runner instead.

Resources