In a previous blog post my colleague Rene Schakmann has shown that Apache Camel is a versatile tool that integrates different components using well-known enterprise integration patterns. At willhaben, we use Apache Camel together with Spring Boot for many different projects. However, writing unit tests for these Camel routes is not that trivial and requires some knowledge of both frameworks. In this blog post, I will walk you through a sample project (available on github) with special regard given to testability.

Setup and configuration

The project is a pretty standard Java Maven project. In order to be able to properly write unit test, we need to use some dependencies (see pom.xml). Apart from the usual Camel and Spring Boot dependencies, the most important ones are:

<dependency>

<groupId>org.apache.camel</groupId>

<artifactId>camel-spring-boot</artifactId>

<version>${camel.version}</version>

</dependency> <dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<version>${spring.boot.version}</version>

<scope>test</scope>

</dependency>

Apache Camel provides a module which integrates nicely into Spring Boot: camel-spring-boot. With this module, we can take full advantage of spring boot features (like autoconfiguration, bulding fat-jars, injecting properties, profiles, etc.). The spring-boot-startet-test dependency helps us with setting up our test cases, which we will see later.

Implementation

Our test project implements one simple Camel route which monitors a folder for new files. So, for example, when the file name contains “cat”, the file is moved to the “cats” folder, and when it contains “dog” it is moved to the “dogs” folder.

To implement this, we use the built-in file component, which uses the URL prefix “file://”. However, to test our business logic we will have to change the endpoint URLs to send test messages via the route directly (instead of consuming from the file endpoint) and verify the output with mock endpoints (and not moving the files), so our AnimalRoute class looks like this:

Our component is pretty minimal and easy to read. Endpoints with double parentheses like “{{animalSource}}” will get injected with values from property files. We will use Spring profiles to change endpoint URLs for development, production and unit testing.

Apart from this route the application consists of just one more class: Main. It serves as an entry point for our application. The only speciality in this class is that we tell spring boot to wait for “Ctrl+C” to stop the application:

Writing Tests

Our unit test will have to do several things:

create the context,

load the correct properties for testing,

inject messages into the route and

verify the result messages.

Luckily we can to this with our setup in one single class only using annotations:

For our tests we want to have the producer endpoint and both consumer endpoints, and we get all of this using the @EndpointInject annotation (note that we again use the curly brackets notation from before). In the test itself we can now easily send a test message, and use the assertion methods of the Camel testing framework to check if the test message got to the right endpoint. The @DirtiesContext annotation ensures that we always get a fresh Camel context for each test.

Now, the only missing pieces are the property files for our environments. With spring profiles, we just have to name our files application-{env}.properties where {env} is the profile which should use this configuration:

animalSource=direct:animalSource dogEndpoint=mock:dogEndpoint catEndpoint=mock:catEndpoint

for application-test.properties

animalSource=file://animals dogEndpoint=file://dogs catEndpoint=file://cats

for application-dev.properties, application-prod.properties, etc…

Conclusion

Although the result is pretty straightforward, understanding all parts and setting up everything can take quite some time. I hope that this post has helped you to gain some insight and will help you get started easily or even start testing right away.