When developing complex Processor
implementations, it is useful to test them in isolation to ensure that they are fully exercised—something that may not necessarily be straightforward in a production route. Likewise, when developing Java classes marked with Camel annotations for bean binding, you want to check the binding logic as well as logic contained within the class. This recipe presents an approach for testing these types of scenarios.
The Java code for this recipe is located in the org.camelcookbook.examples.testing.exchange
package.
Processors are typically used for composite actions that involve modifying the body of an exchange as well as a number of headers. Here is a Processor
implementations process()
method that we would like to test:
@Override public void process(Exchange exchange) throws Exception { final String something = "SOMETHING"; Message in = exchange.getIn(); String action = in.getHeader("action", String.class); if ((action == null) || (action.isEmpty())) { in.setHeader("actionTaken", false); } else { in.setHeader("actionTaken", true); String body = in.getBody(String.class); if (action.equals("append")) { in.setBody(body + " " + something); } else if (action.equals("prepend")) { in.setBody(something + " " + body); } else { throw new IllegalArgumentException( "Unrecognized action requested: [" + action + "]"); } } }
In order to test this processor with an Exchange instance, perform the following steps:
CamelTestSupport
and define an inline route through a RouteBuilder
implementation that contains only that processor:@Override
protected RouteBuilder createRouteBuilder()
throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("direct:in")
.process(new ComplicatedProcessor())
.to("mock:out");
}
};
}
@Test public void testPrepend() throws Exception { MockEndpoint mockOut = getMockEndpoint("mock:out"); mockOut.message(0).body().isEqualTo("SOMETHING text"); mockOut.message(0).header("actionTaken").isEqualTo(true); Map<String, Object> headers = new HashMap<String, Object>(); headers.put("action", "prepend"); template.sendBodyAndHeaders("direct:in", "text", headers); assertMockEndpointsSatisfied(); }
By developing a throwaway route, we have enabled the processor under test to be executed inside an actual Camel context. This allows us to feed sample messages to the processor inside the route using a ProducerTemplate
instance, and check the results using a mock endpoint. This approach distances us from the details of constructing an Exchange object by hand, and instead uses Camel to do it for us.
Camel allows you to invoke bean methods directly from your route via a bean(..)
statement, without needing that you refer to any Camel APIs in the method being invoked. A mechanism called Bean Binding is used to map the contents of the exchange to your method parameters (see the Routing messages directly to a Java method recipe in Chapter 3, Routing to Your Code). Using this mechanism you can access any part of the exchange without relying on the Camel API directly by using Camel's runtime annotations on the method arguments. While the resulting POJO can be tested like any other object, in order to test the bindings, you need to instantiate the bean inside a route and test as done before.
3.12.107.31