Testing a Camel application

Exclusive offer: get 50% off this eBook here
Instant Apache Camel Messaging System [Instant]

Instant Apache Camel Messaging System [Instant] — Save 50%

Tackle integration problems and learn practical ways to make data flow between your application and other systems using Apache Camel with this book and ebook

$14.99    $7.50
by Evgeniy Sharapov | September 2013 | Open Source

In this article by Evgeniy Sharapov, author of the book Instant Apache Camel Messaging System, we will learn about testing a Camel application. Of course, it is very easy to start your application and see how it works while it is small. Once the application starts growing, it will become impossible to check that it works correctly. Furthermore, Camel is both concurrent, which makes it even more complex, and an integration framework, so one would expect inputs and outputs to come and go from and to other systems, which might make things very tedious for the person doing quality assurance. Well, a long time ago, software developers came up with an idea to automate testing. Since then, plenty of good frameworks and libraries facilitating automatic testing have emerged. One of the approaches is unit testing—testing an application's functionality piece by piece or unit by unit. In the Java world, there are two options for unit testing: JUnit and TestNG. Even though Apache Camel supports both, here we will use only JUnit.

(For more resources related to this topic, see here.)

Let's start testing. Apache Camel comes with the Camel Test Kit: some classes leverage testing framework capabilities and extend with Camel specifics.

To test our application, let's add this Camel Test Kit to our list of dependencies in the POM file, as shown in the following code:

<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-test</artifactId> <version>${camel-version}</version> </dependency>

At the same time, if you have any JUnit dependency, the best solution would be to delete it for now so that Maven will resolve the dependency and we will get a JUnit version required by Camel.

Let's rewrite our main program a little bit. Change the class App as shown in the following code:

public class App { public static void main(String[] args) throws Exception { Main m = new Main(); m.addRouteBuilder( new AppRoute() ); m.run(); } static class AppRoute extends RouteBuilder { @Override public void configure() throws Exception { from("stream:in") .to("file:test"); } } }

Instead of having an anonymous class extending RouteBuilder, we made it an inner class. That is, we are not going to test the main program. Instead, we are going to test if our routing works as expected, that is, messages from the system input are routed into the files in the test directory. At the beginning of the test, we will delete the test directory and our assertion will be that we have the directory test after we send the message and that it has exactly one file. To simplify the deleting of the directory test at the beginning of the unit test, we will use FileUtils.deleteDirectory from Apache Commons IO. Let's add it to our list of dependencies:

<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency>

In our project layout, we have a file src/test/java/com/company/AppTest.java. This is a unit test that has been created from the Maven artifact that we used to create our application. Now, let's replace the code inside that file with the following code:

package com.company; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.test.junit4.CamelTestSupport; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import java.io.*; public class AppTest extends CamelTestSupport { static PipedInputStream in; static PipedOutputStream out; static InputStream originalIn; @Test() public void testAppRoute() throws Exception { out.write("This is a test message!\n".getBytes()); Thread.sleep(2000); assertTrue(new File("test").listFiles().length == 1); } @BeforeClass() public static void setup() throws IOException { originalIn = System.in; out = new PipedOutputStream(); in = new PipedInputStream(out); System.setIn(in); FileUtils.deleteDirectory(new File("test")); } @After() public void teardown() throws IOException { out.close(); System.setIn(originalIn); } @Override public boolean isCreateCamelContextPerClass() { return false; } @Override protected RouteBuilder createRouteBuilder() throws Exception { return new App.AppRoute(); } }

Now we can run mvn compile test from the console and see that the test was run and that it is successful:

Some important things to take note of in the code of our unit test are as follows:

  • We have extended the CamelTestSupport class for Junit4 (see the package it is imported from). There are also classes that support TestNG and Junit3.
  • We have overridden the method createRouteBuilder() to return RouteBuilder with our routes.
  • We made our test class create CamelContext for each test method (annotated by @Test) by making isCreateCamelContextPerClass return false.
  • System.in has been substituted with a piped stream in the startup() method and has been set back to the original value in the teardown() method. The trick is in doing it before CamelContext is created and started (now you see why we create CamelContext for each test).

Also, you may see that after we send the message into the output stream piped to System.in, we made the test thread stop for couple of seconds to ensure that the message passes through the routes into the file.

In short, our test running suite overrides System.in with a pipe stream so we can write into System.in from the code and deletes the directory test before the Test class is loaded. After the class is loaded and right before the testAppRoute() method, it creates CamelContext, using routes created by the overridden method createRouteBuilder(). Then it runs the test method which sends bytes of the message into the piped stream so that it gets into System.in where it is read by the Camel (note the \n limiting the message). Camel then does what is written in the routes, that is, creates a file in the test directory. To be sure it's done before we do assertions, we make the thread executing the test sleep for 2 seconds. Then, we assert that we do have a file in the test directory at the end of the test.

Our test works, but you see that it already gets quite hairy with piping streams and making calls to Thread.sleep()—and that's just the beginning. We haven't yet started using external systems, such as FTP servers, web services, and JMS queues. Another concern is the integration of our application with other systems. Some of them may not have a test environment. In this case, we can't easily control the side effects of our application, messages that it sends and receives from those systems; or how the systems interact with our application. To solve this problem, software developers use mocking.

Summary

Thus we learned about testing a Camel application in this article.

Resources for Article:


Further resources on this subject:


Instant Apache Camel Messaging System [Instant] Tackle integration problems and learn practical ways to make data flow between your application and other systems using Apache Camel with this book and ebook
Published: September 2013
eBook Price: $14.99
See more
Select your format and quantity:

About the Author :


Evgeniy Sharapov

Evgeniy Sharapov has been working in the software development field for over 10 years. At the beginning of his career, he wrote software in C and C++ for signals and data processing; he later picked up Java, Python, Ruby, Clojure, and Scala, gradually moving up on the ladder of abstraction levels. For the last few years he has been developing enterprise level applications on Java platform using all sorts of tools and frameworks, such as Spring, Hibernate, iBatis, Drools, JBoss, Webshere, Maven, and Ant, while maintaining interest in fringe software development using Ruby on Rails, TorqueBox, Clojure, and Scala.

Books From Packt


 Instant Apache Wicket 6 [Instant]
Instant Apache Wicket 6 [Instant]

Apache Solr 3.1 Cookbook
Apache Solr 3.1 Cookbook

Apache Axis2 Web Services, 2nd Edition
Apache Axis2 Web Services, 2nd Edition

 Apache Maven 3 Cookbook
Apache Maven 3 Cookbook

 Apache Flume: Distributed Log Collection for Hadoop
Apache Flume: Distributed Log Collection for Hadoop

Instant Apache Solr for Indexing Data How-to [Instant]
Instant Apache Solr for Indexing Data How-to [Instant]

Apache Kafka
Apache Kafka

 Instant Apache Maven Starter [Instant]
Instant Apache Maven Starter [Instant]


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
e
z
S
g
L
E
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software