TestingPage edited by willem jiangChanges (2)
Full ContentTestingTesting is a crucial activity in any piece of software development or integration. Typically Camel Riders use various different technologies wired together in a variety of patterns with different _expression_ languages together with different forms of Bean Integration and Dependency Injection so its very easy for things to go wrong! Camel is a Java library so you can easily wire up tests in whatever unit testing framework you use (JUnit 3.x (deprecated), 4.x, or TestNG). However the Camel project has tried to make the testing of Camel as easy and powerful as possible so we have introduced the following features. Testing mechanismsThe following mechanisms are supported
In all approaches the test classes look pretty much the same in that they all reuse the Camel binding and injection annotations. Camel Test ExampleHere is the Camel Test example. public class FilterTest extends CamelTestSupport { @EndpointInject(uri = "mock:result") protected MockEndpoint resultEndpoint; @Produce(uri = "direct:start") protected ProducerTemplate template; @Test public void testSendMatchingMessage() throws Exception { String expectedBody = "<matched/>"; resultEndpoint.expectedBodiesReceived(expectedBody); template.sendBodyAndHeader(expectedBody, "foo", "bar"); resultEndpoint.assertIsSatisfied(); } @Test public void testSendNotMatchingMessage() throws Exception { resultEndpoint.expectedMessageCount(0); template.sendBodyAndHeader("<notMatched/>", "foo", "notMatchedHeaderValue"); resultEndpoint.assertIsSatisfied(); } @Override protected RouteBuilder createRouteBuilder() { return new RouteBuilder() { public void configure() { from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result"); } }; } } Notice how it derives from the Camel helper class CamelTestSupport but has no Spring or Guice dependency injection configuration but instead overrides the createRouteBuilder() method. Spring Test with XML Config ExampleHere is the Spring Testing example using XML Config. @ContextConfiguration public class FilterTest extends SpringRunWithTestSupport { @EndpointInject(uri = "mock:result") protected MockEndpoint resultEndpoint; @Produce(uri = "direct:start") protected ProducerTemplate template; @DirtiesContext @Test public void testSendMatchingMessage() throws Exception { String expectedBody = "<matched/>"; resultEndpoint.expectedBodiesReceived(expectedBody); template.sendBodyAndHeader(expectedBody, "foo", "bar"); resultEndpoint.assertIsSatisfied(); } @DirtiesContext @Test public void testSendNotMatchingMessage() throws Exception { resultEndpoint.expectedMessageCount(0); template.sendBodyAndHeader("<notMatched/>", "foo", "notMatchedHeaderValue"); resultEndpoint.assertIsSatisfied(); } } Notice that we use @DirtiesContext on the test methods to force Spring Testing to automatically reload the CamelContext after each test method - this ensures that the tests don't clash with each other (e.g. one test method sending to an endpoint that is then reused in another test method). Also notice the use of @ContextConfiguration to indicate that by default we should look for the FilterTest-context.xml on the classpath to configure the test case which looks like this <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd "> <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="direct:start"/> <filter> <xpath>$foo = 'bar'</xpath> <to uri="mock:result"/> </filter> </route> </camelContext> </beans> Spring Test with Java Config ExampleHere is the Spring Testing example using Java Config. @ContextConfiguration( locations = "org.apache.camel.spring.javaconfig.patterns.FilterTest$ContextConfig", loader = JavaConfigContextLoader.class) public class FilterTest extends AbstractJUnit4SpringContextTests { @EndpointInject(uri = "mock:result") protected MockEndpoint resultEndpoint; @Produce(uri = "direct:start") protected ProducerTemplate template; @DirtiesContext @Test public void testSendMatchingMessage() throws Exception { String expectedBody = "<matched/>"; resultEndpoint.expectedBodiesReceived(expectedBody); template.sendBodyAndHeader(expectedBody, "foo", "bar"); resultEndpoint.assertIsSatisfied(); } @DirtiesContext @Test public void testSendNotMatchingMessage() throws Exception { resultEndpoint.expectedMessageCount(0); template.sendBodyAndHeader("<notMatched/>", "foo", "notMatchedHeaderValue"); resultEndpoint.assertIsSatisfied(); } @Configuration public static class ContextConfig extends SingleRouteCamelConfiguration { @Bean public RouteBuilder route() { return new RouteBuilder() { public void configure() { from("direct:start").filter(header("foo").isEqualTo("bar")).to("mock:result"); } }; } } } This is similar to the XML Config example above except that there is no XML file and instead the nested ContextConfig class does all of the configuration; so your entire test case is contained in a single Java class. We currently have to reference by class name this class in the @ContextConfiguration which is a bit ugly. Please vote for SJC-238 to address this and make Spring Test work more cleanly with Spring JavaConfig. Its totally optional but for the ContextConfig implementation we derive from SingleRouteCamelConfiguration which is a helper Spring Java Config class which will configure the CamelContext for us and then register the RouteBuilder we create. Spring Test with XML Config and Declarative Configuration ExampleHere is a Camel test support enhanced Spring Testing example using XML Config and pure Spring Test based configuration of the Camel Context. @RunWith(CamelSpringJUnit4ClassRunner.class) @ContextConfiguration // Put here to prevent Spring context caching across tests and test methods since some tests inherit // from this test and therefore use the same Spring context. Also because we want to reset the // Camel context and mock endpoints between test methods automatically. @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) public class CamelSpringJUnit4ClassRunnerPlainTest { @Autowired protected CamelContext camelContext; @Autowired protected CamelContext camelContext2; @EndpointInject(uri = "mock:a", context = "camelContext") protected MockEndpoint mockA; @EndpointInject(uri = "mock:b", context = "camelContext") protected MockEndpoint mockB; @EndpointInject(uri = "mock:c", context = "camelContext2") protected MockEndpoint mockC; @Produce(uri = "direct:start", context = "camelContext") protected ProducerTemplate start; @Produce(uri = "direct:start2", context = "camelContext2") protected ProducerTemplate start2; @Test public void testPositive() throws Exception { assertEquals(ServiceStatus.Started, camelContext.getStatus()); assertEquals(ServiceStatus.Started, camelContext2.getStatus()); mockA.expectedBodiesReceived("David"); mockB.expectedBodiesReceived("Hello David"); mockC.expectedBodiesReceived("David"); start.sendBody("David"); start2.sendBody("David"); MockEndpoint.assertIsSatisfied(camelContext); } @Test public void testJmx() throws Exception { assertEquals(DefaultManagementStrategy.class, camelContext.getManagementStrategy().getClass()); } @Test public void testShutdownTimeout() throws Exception { assertEquals(10, camelContext.getShutdownStrategy().getTimeout()); assertEquals(TimeUnit.SECONDS, camelContext.getShutdownStrategy().getTimeUnit()); } @Test public void testStopwatch() { StopWatch stopWatch = StopWatchTestExecutionListener.getStopWatch(); assertNotNull(stopWatch); assertTrue(stopWatch.taken() < 100); } @Test public void testExcludedRoute() { assertNotNull(camelContext.getRoute("excludedRoute")); } @Test public void testProvidesBreakpoint() { assertNull(camelContext.getDebugger()); assertNull(camelContext2.getDebugger()); } @SuppressWarnings("deprecation") @Test public void testLazyLoadTypeConverters() { assertTrue(camelContext.isLazyLoadTypeConverters()); assertTrue(camelContext2.isLazyLoadTypeConverters()); } } Notice how a custom test runner is used with the @RunWith annotation to support the features of CamelTestSupport through annotations on the test class. See Spring Testing for a list of annotations you can use in your tests. Blueprint TestHere is the Blueprint Testing example using XML Config. // to use camel-test-blueprint, then extend the CamelBlueprintTestSupport class, // and add your unit tests methods as shown below. public class DebugBlueprintTest extends CamelBlueprintTestSupport { // override this method, and return the location of our Blueprint XML file to be used for testing @Override protected String getBlueprintDescriptor() { return "org/apache/camel/test/blueprint/camelContext.xml"; } // here we have regular Junit @Test method @Test public void testRoute() throws Exception { // set mock expectations getMockEndpoint("mock:a").expectedMessageCount(1); // send a message template.sendBody("direct:start", "World"); // assert mocks assertMockEndpointsSatisfied(); } } Also notice the use of getBlueprintDescriptors to indicate that by default we should look for the camelContext.xml in the package to configure the test case which looks like this <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> <camelContext xmlns="http://camel.apache.org/schema/blueprint"> <route> <from uri="direct:start"/> <transform> <simple>Hello ${body}</simple> </transform> <to uri="mock:a"/> </route> </camelContext> </blueprint> Testing endpointsCamel provides a number of endpoints which can make testing easier.
The main endpoint is the Mock endpoint which allows expectations to be added to different endpoints; you can then run your tests and assert that your expectations are met at the end. Stubbing out physical transport technologiesIf you wish to test out a route but want to avoid actually using a real physical transport (for example to unit test a transformation route rather than performing a full integration test) then the following endpoints can be useful.
Testing existing routesCamel provides some features to aid during testing of existing routes where you cannot or will not use Mock etc. For example you may have a production ready route which you want to test with some 3rd party API which sends messages into this route.
Change Notification Preferences
View Online
|
View Changes
|
Add Comment
|
- [CONF] Apache Camel > Testing confluence
- [CONF] Apache Camel > Testing confluence
- [CONF] Apache Camel > Testing confluence
- [CONF] Apache Camel > Testing Daniel Kulp (Confluence)