| [[SpringTesting-SpringTesting]] |
| = Spring Testing |
| |
| Testing is a crucial part of any development or |
| integration work. The Spring Framework offers a number of features that |
| makes it easy to test while using Spring for Inversion of Control which |
| works with JUnit 3.x or JUnit 4.x. |
| |
| We can use Spring for IoC and the Camel xref:components::mock-component.adoc[Mock] and |
| xref:components::test.adoc[Test] endpoints to create sophisticated integration/unit |
| tests that are easy to run and debug inside your IDE. There are three |
| supported approaches for testing with Spring in Camel. |
| |
| [width="100%",cols="10%,10%,10%,60%",options="header",] |
| |======================================================================= |
| |Name |Testing Frameworks Supported |Description |Required Camel Test Dependencies |
| |
| |CamelSpringTestSupport |* JUnit 3.x (deprecated) |
| * JUnit 4.x |
| |Provided by org.apache.camel.test.CamelSpringTestSupport and |
| org.apache.camel.test.junit4.CamelSpringTestSupport. These base classes |
| provide feature parity with the simple |
| CamelTestSupport classes from Camel Test but do |
| not support Spring annotations on the test class such as |
| *@Autowired*, *@DirtiesContext*, and *@ContextConfiguration*. |* JUnit 3.x (deprecated) - camel-test-spring |
| * JUnit 4.x - camel-test-spring |
| |
| |Plain Spring Test |* JUnit 3.x |
| * JUnit 4.x |
| |Extend the abstract base classes |
| (org.springframework.test.context.junit38.AbstractJUnit38SpringContextTests, org.springframework.test.context.junit38.AbstractJUnit4SpringContextTests, |
| etc.) provided in Spring Test or use the Spring Test JUnit4 runner. |
| These approaches support both the Camel annotations and Spring |
| annotations, but do not have feature parity |
| with org.apache.camel.test.CamelTestSupport and |
| org.apache.camel.test.junit4.CamelTestSupport. |* JUnit 3.x (deprecated) - None |
| * JUnit 4.x - None |
| |
| |Camel Enhanced Spring Test |* JUnit 4.x - *Camel 2.10* |
| |Use the org.apache.camel.test.junit4.CamelSpringJUnit4ClassRunner runner |
| with the *@RunWith* annotation to enable |
| feature parity with |
| org.apache.camel.test.CamelTestSupport and |
| org.apache.camel.test.junit4.CamelTestSupport and also support the full |
| suite of Spring Test annotations such |
| as *@Autowired*, *@DirtiesContext*, and *@ContextConfiguration*. |* JUnit 3.x (deprecated) - camel-test-spring |
| * JUnit 4.x - camel-test-spring |
| |======================================================================= |
| |
| [[SpringTesting-CamelSpringTestSupport]] |
| == CamelSpringTestSupport |
| |
| org.apache.camel.test.CamelSpringTestSupport and |
| org.apache.camel.test.junit4.CamelSpringTestSupport extend their non-Spring |
| aware counterparts (org.apache.camel.test.CamelTestSupport and |
| org.apache.camel.test.junit4.CamelTestSupport) and deliver integration with |
| Spring into your test classes. Instead of instantiating the |
| CamelContext and routes programmatically, these classes rely on a Spring |
| context to wire the needed components together. If your test extends |
| one of these classes, you must provide the Spring context by |
| implementing the following method. |
| |
| [source,java] |
| ------------------------------------------------------------------------- |
| protected abstract AbstractApplicationContext createApplicationContext(); |
| ------------------------------------------------------------------------- |
| |
| You are responsible for the instantiation of the Spring context in the |
| method implementation. All of the features available in the non-Spring |
| aware counterparts from Camel Test are available |
| in your test. |
| |
| [[SpringTesting-PlainSpringTest]] |
| == Plain Spring Test |
| |
| In this approach, your test classes directly inherit from the Spring |
| Test abstract test classes or use the JUnit 4.x test runner provided in |
| Spring Test. This approach supports dependency injection into your test |
| class and the full suite of Spring Test annotations but does not support |
| the features provided by the CamelSpringTestSupport classes. |
| |
| [[SpringTesting-PlainSpringTestusingJUnit3.xwithXMLConfigExample]] |
| === Plain Spring Test using JUnit 3.x with XML Config Example |
| |
| Here is a simple unit test using JUnit 3.x support from Spring Test |
| using http://svn.apache.org/repos/asf/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/patterns/FilterTest.java[XML |
| Config]. |
| |
| 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 http://svn.apache.org/repos/asf/camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/patterns/FilterTest-context.xml[FilterTest-context.xml |
| on the classpath] to configure the test case which looks like this |
| |
| This test will load a Spring XML configuration file |
| calledFilterTest-context.xml from the classpath in the same package |
| structure as the FilterTest class and initialize it along with any Camel |
| routes we define inside it, then inject theCamelContextinstance into our |
| test case. |
| |
| For instance, like this maven folder layout: |
| |
| [source,java] |
| -------------------------------------------------------------------------- |
| src/test/java/org/apache/camel/spring/patterns/FilterTest.java |
| src/test/resources/org/apache/camel/spring/patterns/FilterTest-context.xml |
| -------------------------------------------------------------------------- |
| |
| [[SpringTesting-PlainSpringTestusingJUnit4.xwithJavaConfigExample]] |
| === Plain Spring Test using JUnit 4.x with Java Config Example |
| |
| You can completely avoid using an XML configuration file by using |
| Spring Java Config. Here is a unit test |
| using JUnit 4.x support from Spring Test |
| using http://svn.apache.org/repos/asf/camel/trunk/components/camel-spring-javaconfig/src/test/java/org/apache/camel/spring/javaconfig/patterns/FilterTest.java[Java |
| Config]. |
| |
| 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 |
| http://jira.springframework.org/browse/SJC-238[SJC-238] to address this |
| and make Spring Test work more cleanly with Spring JavaConfig. |
| |
| [[SpringTesting-PlainSpringTestusingJUnit4.0.xRunnerwithXMLConfig]] |
| === Plain Spring Test using JUnit 4.0.x Runner with XML Config |
| |
| You can avoid extending Spring classes by using the |
| SpringJUnit4ClassRunner provided by Spring Test. This custom JUnit |
| runner means you are free to choose your own class hierarchy while |
| retaining all the capabilities of Spring Test. |
| |
| INFO:This is for Spring 4.0.x. If you use Spring 4.1 or newer, then see the |
| next section. |
| |
| [source,java] |
| ------------------------------------------------------ |
| @RunWith(SpringJUnit4ClassRunner.class) |
| @ContextConfiguration |
| public class MyCamelTest { |
| |
| @Autowired |
| protected CamelContext camelContext; |
| |
| @EndpointInject("mock:foo") |
| protected MockEndpoint foo; |
| |
| |
| @Test |
| @DirtiesContext |
| public void testMocksAreValid() throws Exception { |
| ... |
| |
| foo.message(0).header("bar").isEqualTo("ABC"); |
| |
| MockEndpoint.assertIsSatisfied(camelContext); |
| } |
| } |
| ------------------------------------------------------ |
| |
| [[SpringTesting-PlainSpringTestusingJUnit4.1.xRunnerwithXMLConfig]] |
| === Plain Spring Test using JUnit 4.1.x Runner with XML Config |
| |
| You can avoid extending Spring classes by using the |
| SpringJUnit4ClassRunner provided by Spring Test. This custom JUnit |
| runner means you are free to choose your own class hierarchy while |
| retaining all the capabilities of Spring Test. |
| |
| INFO:When using Spring 4.1 onwards, you need to use the @BootstrapWith |
| annotation to configure it to use Camel testing, as shown below. |
| |
| [source,java] |
| ------------------------------------------------------ |
| @RunWith(CamelSpringJUnit4ClassRunner.class) |
| @BootstrapWith(CamelTestContextBootstrapper.class) |
| @ContextConfiguration |
| public class MyCamelTest { |
| |
| @Autowired |
| protected CamelContext camelContext; |
| |
| @EndpointInject("mock:foo") |
| protected MockEndpoint foo; |
| |
| |
| @Test |
| @DirtiesContext |
| public void testMocksAreValid() throws Exception { |
| ... |
| |
| foo.message(0).header("bar").isEqualTo("ABC"); |
| |
| MockEndpoint.assertIsSatisfied(camelContext); |
| } |
| } |
| ------------------------------------------------------ |
| |
| [[SpringTesting-CamelEnhancedSpringTest]] |
| == Camel Enhanced Spring Test |
| |
| Using org.apache.camel.test.junit4.CamelSpringJUnit4ClassRunner runner |
| with the *@RunWith* annotation provides |
| the full feature set of Spring Test with support for the feature set |
| provided in the CamelTestSupport classes. A number of Camel specific |
| annotations have been developed in order to provide for declarative |
| manipulation of the Camel context(s) involved in the test. These |
| annotations free your test classes from having to inherit from the |
| CamelSpringTestSupport classes and also reduce the amount of code |
| required to customize the tests. |
| |
| [width="100%",cols="20%,20%,20%,20%,20%",options="header",] |
| |======================================================================= |
| |Annotation Class |Applies To |Description |Default Behavior If Not Present |Default Behavior If Present |
| |
| |org.apache.camel.test.spring.DisableJmx |Class |Indicates if JMX should be globally disabled in the CamelContexts that |
| are bootstrapped during the test through the use of Spring Test loaded |
| application contexts. |JMX is disabled |JMX is disabled |
| |
| |org.apache.camel.test.spring.ExcludeRoutes |Class |Indicates if certain route builder classes should be excluded from |
| discovery. Initializes a |
| org.apache.camel.spi.PackageScanClassResolver to exclude a set of given |
| classes from being resolved. Typically this is used at test time to |
| exclude certain routes, which might otherwise be just noisy, from being |
| discovered and initialized. |Not enabled and no routes are excluded |No routes are excluded |
| |
| |org.apache.camel.test.spring.MockEndpoints |Class |Triggers the auto-mocking of endpoints whose URIs match the provided |
| filter. The default filter is "*" which matches all endpoints. |
| See org.apache.camel.impl.InterceptSendToMockEndpointStrategy for more |
| details on the registration of the mock endpoints. |Not enabled |All endpoints are sniffed and recorded in a mock endpoint. |
| |
| |org.apache.camel.test.spring.MockEndpointsAndSkip |Class |Triggers the auto-mocking of endpoints whose URIs match the provided |
| filter. The default filter is "*", which matches all endpoints. |
| See https://github.com/apache/camel/blob/master/camel-core/src/main/java/org/apache/camel/impl/InterceptSendToMockEndpointStrategy.java[org.apache.camel.impl.InterceptSendToMockEndpointStrategy] for more |
| details on the registration of the mock endpoints. This annotation will |
| also skip sending the message to matched endpoints as well. |Not enabled |All endpoints are sniffed and recorded in a mock endpoint. The original |
| endpoint is not invoked. |
| |
| |org.apache.camel.test.spring.ProvidesBreakpoint |Method |Indicates that the annotated method returns |
| an org.apache.camel.spi.Breakpoint for use in the test. Useful for |
| intercepting traffic to all endpoints or simply for setting a break |
| point in an IDE for debugging. The method must be public, static, take |
| no arguments, and return org.apache.camel.spi.Breakpoint. |N/A |The returned Breakpoint is registered in the CamelContext(s) |
| |
| |org.apache.camel.test.spring.ShutdownTimeout |Class |Indicates to set the shutdown timeout of all CamelContexts instantiated |
| through the use of Spring Test loaded application contexts. If no |
| annotation is used, the timeout is automatically reduced to 10 seconds |
| by the test framework. |10 seconds |10 seconds |
| |
| |org.apache.camel.test.spring.UseAdviceWith |Class |Indicates the use of adviceWith() within the test class. If a class is |
| annotated with this annotation and UseAdviceWith#value() returns true, |
| any CamelContexts bootstrapped during the test through the use of Spring |
| Test loaded application contexts will not be started automatically. The |
| test author is responsible for injecting the Camel contexts into the |
| test and executing CamelContext#start() on them at the appropriate time |
| after any advice has been applied to the routes in the CamelContext(s). |CamelContexts do not automatically start. |CamelContexts do not automatically start. |
| |
| |org.apache.camel.test.spring.UseOverridePropertiesWithPropertiesComponent |Method |*Camel 2.16:*Indicates that the annotated method returns a |
| java.util.Properties for use in the test, and that those properties |
| override any existing properties configured on the PropertiesComponent | | Override properties |
| |======================================================================= |
| |
| The following example illustrates the use of the |
| *@MockEndpoints* annotation in order to setup mock endpoints as |
| interceptors on all endpoints using the Camel Log component and the |
| *@DisableJmx* annotation to enable JMX which is disabled during tests by |
| default. Note that we still use the *@DirtiesContext* annotation to |
| ensure that the CamelContext, routes, and mock endpoints are |
| reinitialized between test methods. |
| |
| [source,java] |
| ---------------------------------------------------------------------------------------------------- |
| @RunWith(CamelSpringJUnit4ClassRunner.class) |
| @BootstrapWith(CamelTestContextBootstrapper.class) |
| @ContextConfiguration |
| @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) |
| @MockEndpoints("log:*") |
| @DisableJmx(false) |
| public class CamelSpringJUnit4ClassRunnerPlainTest { |
| |
| @Autowired |
| protected CamelContext camelContext2; |
| |
| protected MockEndpoint mockB; |
| |
| @EndpointInject(value = "mock:c", context = "camelContext2") |
| protected MockEndpoint mockC; |
| |
| @Produce(uri = "direct:start2", context = "camelContext2") |
| protected ProducerTemplate start2; |
| |
| @EndpointInject(value = "mock:log:org.apache.camel.test.junit4.spring", context = "camelContext2") |
| protected MockEndpoint mockLog; |
| |
| @Test |
| public void testPositive() throws Exception { |
| |
| mockC.expectedBodiesReceived("David"); |
| mockLog.expectedBodiesReceived("Hello David"); |
| |
| start2.sendBody("David"); |
| |
| MockEndpoint.assertIsSatisfied(camelContext); |
| } |
| ---------------------------------------------------------------------------------------------------- |
| |
| [[SpringTesting-AddingmoreMockexpectations]] |
| == Adding more Mock expectations |
| |
| If you wish to programmatically add any new assertions to your test you |
| can easily do so with the following. Notice how we use @EndpointInject |
| to inject a Camel endpoint into our code then the xref:components::mock-component.adoc[Mock] |
| API to add an expectation on a specific message. |
| |
| [source,java] |
| -------------------------------------------------------------------- |
| @ContextConfiguration |
| public class MyCamelTest extends AbstractJUnit38SpringContextTests { |
| |
| @Autowired |
| protected CamelContext camelContext; |
| |
| @EndpointInject("mock:foo") |
| protected MockEndpoint foo; |
| |
| public void testMocksAreValid() throws Exception { |
| // lets add more expectations |
| foo.message(0).header("bar").isEqualTo("ABC"); |
| |
| MockEndpoint.assertIsSatisfied(camelContext); |
| } |
| } |
| -------------------------------------------------------------------- |
| |
| [[SpringTesting-Furtherprocessingthereceivedmessages]] |
| == Further processing the received messages |
| |
| Sometimes once a xref:components::mock-component.adoc[Mock] endpoint has received some |
| messages you want to then process them further to add further assertions |
| that your test case worked as you expect. |
| |
| So you can then process the received message exchanges if you like... |
| |
| [source,java] |
| -------------------------------------------------------------------- |
| @ContextConfiguration |
| public class MyCamelTest extends AbstractJUnit38SpringContextTests { |
| |
| @Autowired |
| protected CamelContext camelContext; |
| |
| @EndpointInject("mock:foo") |
| protected MockEndpoint foo; |
| |
| public void testMocksAreValid() throws Exception { |
| // lets add more expectations... |
| |
| MockEndpoint.assertIsSatisfied(camelContext); |
| |
| // now lets do some further assertions |
| List<Exchange> list = foo.getReceivedExchanges(); |
| for (Exchange exchange : list) { |
| Message in = exchange.getIn(); |
| ... |
| } |
| } |
| } |
| -------------------------------------------------------------------- |
| |
| [[SpringTesting-Sendingandreceivingmessages]] |
| == Sending and receiving messages |
| |
| It might be that the |
| xref:enterprise-integration-patterns.adoc[Enterprise Integration |
| Patterns] you have defined in either Spring XML or |
| using the Java DSL do all of the sending and receiving |
| and you might just work with the xref:components::mock-component.adoc[Mock] endpoints as |
| described above. However sometimes in a test case its useful to |
| explicitly send or receive messages directly. |
| |
| To send or receive messages you should use the |
| Bean Integration mechanism. For example to |
| send messages inject a ProducerTemplate using the @EndpointInject |
| annotation then call the various send methods on this object to send a |
| message to an endpoint. To consume messages use the @MessageDriven |
| annotation on a method to have the method invoked when a message is |
| received. |
| |
| [source,java] |
| -------------------------------------------------- |
| public class Foo { |
| @EndpointInject(uri="activemq:foo.bar") |
| ProducerTemplate producer; |
| |
| public void doSomething() { |
| // lets send a message! |
| producer.sendBody("<hello>world!</hello>"); |
| } |
| |
| // lets consume messages from the 'cheese' queue |
| @MessageDriven(uri="activemq:cheese") |
| public void onCheese(String name) { |
| ... |
| } |
| } |
| -------------------------------------------------- |
| |