How to use mockito in ExchangeTestSupport - apache-camel

I have camel route as below
public class MainRouteBuilder extends RouteBuilder {
#Autowired
private CcsRouteCommonProperties commonProps;
/**
* {#inheritDoc}
*/
#Override
public void configure() throws Exception {
}
}
I have written test using ExchangeTestSupport as below
public class MainRouteBuilderTest extends ExchangeTestSupport {
/**
* {#inheritDoc}
*/
#Override
public RoutesBuilder createRouteBuilder() throws Exception {
}
#Test
public void shouldProcess() throws Exception {
}
}
I am trying to mock CcsRouteCommonProperties something like below
#Mock
private CcsRouteCommonProperties commonProps;
How to mock the above field using mockito(#RunWith(MockitoJUnitRunner.class))

Direct answer to your question would be to Use #InjectMocks on MainRouteBuilder and let Mockito inject an #Mock or #Spy of CcsRouteCommonProperties. I hope this short guide shall explain it for you.
Solution would be something like
#RunWith(MockitoJUnitRunner.class)
public class MainRouteBuilderTest extends ExchangeTestSupport {
#Mock
CcsRouteCommonProperties commonProps;
#InjectMocks
MainRouteBuilder routeBuilder;
#Override
public RoutesBuilder createRouteBuilder() throws Exception {
return routeBuilder;
}
#Test
public void shouldProcess() throws Exception {
when(commonProps.getSomething()).thenReturn(new Something());
}
}
However, if I am in your place, I'd avoid #Autowired magic and use clearly stated dependencies using constructor injection.
Route Builder
public class MainRouteBuilder extends RouteBuilder {
private CcsRouteCommonProperties commonProps;
public MainRouteBuilder( CcsRouteCommonProperties commonProps) {
this.commonProps = commonProps;
}
/**
* {#inheritDoc}
*/
#Override
public void configure() throws Exception {
}
}
Test
#RunWith(MockitoJUnitRunner.class)
public class MainRouteBuilderTest extends ExchangeTestSupport {
#Mock
CcsRouteCommonProperties commonProps;
#Override
public RoutesBuilder createRouteBuilder() throws Exception {
return new MainRouteBuilder(commonProps);
}
#Test
public void shouldProcess() throws Exception {
}
}

Related

Unit test Apache Camel specific routes by filtering (Model#setRouteFilter)

How to include only certain routes in my unit test. For example, how do I enable only my-translation-route.
public class TestRoute extends RouteBuilder {
#Override
public void configure() {
from("ftp://my-ftp-server:21/messages")
.routeId("my-inbound-route")
.to("direct:my-translation-route");
from("direct:my-translation-route")
.routeId("my-translation-route")
.bean(MyBean.class)
.to("direct:my-outbound-route");
from ("direct:my-outbound-route")
.routeId("my-translation-route")
.to("http://my-http-server:8080/messages");
}
}
I tried with Model#filterRoutes but this did not work. All routes were loaded.
class TestRouteTest extends CamelTestSupport {
#Override
protected RoutesBuilder createRouteBuilder() {
return new TestRoute();
}
#Override
public boolean isUseAdviceWith() {
return true;
}
#Test
void testIfItWorks() throws Exception {
context.setRouteFilterPattern("my-translation-route", null);
AdviceWith.adviceWith(context, "my-translation-route", a -> {
a.mockEndpointsAndSkip("direct:my-outbound-route");
});
context.start();
getMockEndpoint("mock:direct:my-outbound-route").expectedBodyReceived().expression(constant("Hahaha! 42"));
template.sendBodyAndHeaders("direct:my-translation-route", "42", null);
assertMockEndpointsSatisfied();
}
}
I got it working with the override of CamelTestSupport#getRouteFilterIncludePattern, e.g.:
#Override
public String getRouteFilterIncludePattern() {
return "direct:my-translation-route";
}
But then this is set for all tests in this test class.
Possible (stupid) solution : set a conditional auto startup for your routes, whose value depends on a (Camel or JVM) property that you can set with a particular value during the unit tests:
public class TestRoute extends RouteBuilder {
#PropertyInject(name="productionMode", defaultValue="true")
private boolean productionMode;
#Override
public void configure() {
from("ftp://my-ftp-server:21/messages")
...
.autoStartUp(productionMode); // <=here
}
}
There are various ways to override properties during your tests. See https://camel.apache.org/components/3.17.x/properties-component.html

JMS property breadcrumbId

How can I put breadcrumb that I have generated into this property? for example I've this class:
public class MyRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
String uuid = getContext().getUuidGenerator().generateUuid();
from("someRoute")to("activemq:queue:someQueue");
}
}
and my question is. How can i put uuid as jms property breadcrumbId?
This should do it
#Override
public void configure() throws Exception {
String uuid = getContext().getUuidGenerator().generateUuid();
from("someRoute").setHeader(Exchange.BREADCRUMB_ID, simple(uuid)).to("activemq:queue:someQueue");
}

Apache Camel: all modifications of onRedelivery's processor is reset in next redelivery

All modifications of onRedelivery's processor is reset in next redelivery. Is there any way to make the modifications becomes permanent?
Properties are kept at each redelivery. You can use them to store information that you want to use after.
Code :
public class OnRedeliveryTest extends CamelTestSupport {
public static final String PROP_TEST = "PROP_TEST";
#Produce(uri = "direct:start")
ProducerTemplate producerTemplate;
#Override
public RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
onException(Exception.class)
.onRedelivery(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
final String current = (String) exchange.getProperty(PROP_TEST);
exchange.setProperty(PROP_TEST, "property" + current);
System.out.println((String) exchange.getProperty(PROP_TEST));
}
})
.maximumRedeliveries(3).redeliveryDelay(0)
.handled(true)
.end();
from("direct:start")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
}
})
.throwException(new Exception("BOOM"))
.to("mock:end");
}
};
}
#Test
public void smokeTest() throws Exception {
producerTemplate.sendBody("1");
}
}
In output, you will have :
propertynull
propertypropertynull
propertypropertypropertynull

Doing bean inject in camel test

I have a camel app which look something like below which has a route like below:-
from("direct:getMarketplaceOrders").to("bean:orderHelper?method=getMarketplaceOrders");
The entry point of the code look something like below:
public class OrderMainApp {
public static void main(String... args) throws Exception {
OrderMainApp orderMainApp = new OrderMainApp();
DefaultCamelContext camelContext = new DefaultCamelContext();
ProducerTemplate producer = camelContext.createProducerTemplate();
camelContext.setRegistry(orderMainApp.createRegistry(producer));
camelContext.addRoutes(new OrderRouteBuilder(producer));
camelContext.start();
}
protected JndiRegistry createRegistry(ProducerTemplate producer) throws Exception {
JndiRegistry jndi = new JndiRegistry();
OrderHelper orderHelper = new OrderHelper();
orderHelper.setProducer(producer);
jndi.bind("orderHelper", orderHelper);
return jndi;
}
}
In OrderRouteBuilder configure has routes like below:-
//processor is a custom JSONProcessor extending Processor
from("jetty:http://localhost:8888/orchestratorservice").process(processor);
from("direct:getMarketplaceOrders").to("bean:orderHelper?method=getMarketplaceOrders");
My goal is to test the response I receive from bean:orderHelper?method=getMarketplaceOrders when I place a request on direct:getMarketplaceOrders
orderHelper.getMarketplaceOrders looks like below:-
public OrderResponse getMarketplaceOrders(GetMarketplaceOrdersRequest requestParam) throws Exception
My test class look something like below:-
public class OrderMainAppTest extends CamelTestSupport {
#Produce(uri = "direct:getMarketplaceOrders")
protected ProducerTemplate template;
#EndpointInject(uri = "bean:orderHelper?method=getMarketplaceOrders")
protected MockEndpoint resultEndpoint;
#Test
public void testSendMatchingMessage() throws Exception {
String expectedBody = "<matched/>";
template.sendBody("{\"fromDateTime\": \"2016-01-11 10:12:13\"}");
resultEndpoint.expectedBodiesReceived(expectedBody);
resultEndpoint.assertIsSatisfied();
}
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() {
from("direct:getMarketplaceOrders").to("bean:orderHelper?method=getMarketplaceOrders");
}
};
}
}
Whenever I am running the test I am getting the below exception:-
java.lang.IllegalArgumentException: Invalid type: org.apache.camel.component.mock.MockEndpoint which cannot be injected via #EndpointInject/#Produce for: Endpoint[bean://orderHelper?method=getMarketplaceOrders]
I am guessing this is because I am not able to pass on OrderHelper to the camel test context. Can some one let me know how can I inject the bean in the mock result end point?
EDIT:-
I tried modifying my test class as follows:-
public class OrderMainAppTest extends CamelTestSupport {
protected OrderHelper orderHelper = new OrderHelper();
#Produce(uri = "direct:getMarketplaceOrders")
protected ProducerTemplate template;
#EndpointInject(uri = "mock:intercepted")
MockEndpoint mockEndpoint;
#Before
public void preSetup() throws Exception {
orderHelper.setProducer(template);
};
#Test
public void testSendMatchingMessage() throws Exception {
GetMarketplaceOrdersRequest request = new GetMarketplaceOrdersRequest();
request.setFromDateTime("2016-01-11 10:12:13");
request.setApikey("secret_key");
request.setMethod("getMarketplaceOrders");
request.setLimit(10);
request.setOffset(2);
template.sendBody(request);
mockEndpoint.expectedBodiesReceived("{\"success\":\"false\"");
}
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() {
interceptSendToEndpoint("bean:orderHelper?method=getMarketplaceOrders")
.to("mock:intercepted"); from("direct:getMarketplaceOrders").to("bean:orderHelper?method=getMarketplaceOrders");
}
};
}
#Override
protected JndiRegistry createRegistry() throws Exception {
return getRegistry();
}
protected JndiRegistry getRegistry() {
JndiRegistry jndi = new JndiRegistry();
jndi.bind("orderHelper", orderHelper);
return jndi;
}
}
The above code is making the request correctly and is flowing through my app correctly. But I am not able to intercept the response of orderHelper.getMarketplaceOrders. The above code is intercepting only the request. I tried changing to template.requestBody(request). But still no luck.
This error means you can't inject a bean: endpoint into a MockEndpoint.
If you want to "intercept" the call into your OrderHelper, you can use interceptSendToEndpoint in your route :
#EndpointInject(uri = "mock:intercepted")
MockEndpoint mockEndpoint;
...
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() {
interceptSendToEndpoint("bean:orderHelper?method=getMarketplaceOrders")
.to("mock:intercepted");
from("direct:getMarketplaceOrders")
.to("bean:orderHelper?method=getMarketplaceOrders");
}
};
See : http://camel.apache.org/intercept.html
By updating my createRouteBuilder as shown below. I am able to intercept the response and send it to a mock endpoint where I can do the assertion.
#Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
#Override
public void configure() {
from("direct:getMarketplaceOrders").to("bean:orderHelper?method=getMarketplaceOrders").onCompletion()
.to("mock:intercepted");
}
};
}

Camel test using Intercept

I am trying to intercept a message to skip the Http request and proceed with my route.
Below is the class you can copy/paste to try it out.
Using camel-test, camel-core, camel-http4 2.10.2 and httpclient-osgi, httpcore-osgi 4.2.2
Here is the code :
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.AdviceWithRouteBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
/**
* Created with IntelliJ IDEA.
* User: lleclerc
* Date: 12-11-28
* Time: 16:34
* To change this template use File | Settings | File Templates.
*/
public class IsUseAdviceWithJUnit4Test extends CamelTestSupport {
private String providerEndPointURI = "http://stackoverflow.com";
private String timerEndPointURI = "timer://myTimer";
private String mockEndPointURI = "mock:myMock";
private String directEndPointURI = "direct:myDirect";
private boolean messageIntercepted;
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from(timerEndPointURI + "?fixedRate=true&delay=1000&period=1000")
.to(providerEndPointURI + "?throwExceptionOnFailure=false")
.to(mockEndPointURI);
}
};
}
#Test
public void testIsUseAdviceWith() throws Exception {
messageIntercepted = false;
context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith(directEndPointURI);
mockEndpoints();
interceptSendToEndpoint(providerEndPointURI)
.skipSendToOriginalEndpoint()
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
messageIntercepted = true;
System.out.println("INTERCEPTED");
}
});
}
});
// we must manually start when we are done with all the advice with
context.start();
getMockEndpoint(mockEndPointURI).expectedMessageCount(1);
template.sendBody(directEndPointURI, "a trigger");
assertMockEndpointsSatisfied();
assertEquals(true, messageIntercepted);
assertNotNull(context.hasEndpoint(directEndPointURI));
assertNotNull(context.hasEndpoint("mock:" + directEndPointURI));
assertNotNull(context.hasEndpoint(mockEndPointURI));
}
#Override
public boolean isUseAdviceWith() {
return true;
}
#Override
public boolean isUseRouteBuilder() {
return true;
}
}
Thank you for your help !
There was bugs inside camel-http4.
http://camel.465427.n5.nabble.com/Found-a-bug-with-camel-http4-td5723733.html
http://camel.465427.n5.nabble.com/Test-Intercept-with-adviceWith-and-http-td5723473.html

Resources