Test Blueprint
Since Camel 2.10
camel-test-blueprint does only support testing one CamelContext. So if you have two or more CamelContexts in your blueprint XML files, then only the CamelContext first found is used during testing.
Testing is a crucial part of any development or integration work. Camel supports the definition of Blueprint routes, but given that Blueprint is an OSGi specific technology, writing unit tests is quite difficult. This library leverages PojoSR (now Felix Connect) which provides a service registry without using a fully compliant OSGi container. This allows defining real unit tests (as opposed to integration tests using Pax Exam. Please make sure all test jars in your classpath are OSGi bundles.
Also notice the use of getBlueprintDescriptor
to specify the
location of the OSGi Blueprint XML file.
If you have multiple OSGi Blueprint XML files, then you can specify them with a comma-separated list in the *`getBlueprintDescriptor`* method. Notice that only **one** `CamelContext` is supported per blueprint bundle, so if you have multiple XML files then only one of them should have `<camelContext>`.
Here’s the Blueprint XML file:
In order to define blueprint tests, add the following dependency to your pom:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-blueprint</artifactId>
<version>2.10</version>
<scope>test</scope>
</dependency>
Classpath scanning
By default PojoSR test container scans the test classpath for all the
OSGi bundles available there. All the bundles with Blueprint descriptor
files will be automatically started by the test container. If you would
like to prevent particular bundles from being started by the test
container, override the getBundleFilter
method, just as demonstrated
in the snippet below.
@Override
protected String getBundleFilter() {
// I don't want test container to scan and load Logback bundle during the test
return "(!(Bundle-SymbolicName=ch.qos.logback.core))";
}
Keep in mind that not specifying the Blueprint descriptor in the
getBlueprintDescriptor method will not prevent the test container from
loading a given descriptor. The getBundleFilter
method is the proper
way of filtering out bundles you don’t want to start during the test.
Setting timeout when getting CamelContext
Since Camel 2.13.0/2.12.1/2.11.2
CamelBlueprintTestSupport
waits 30 seconds for Camel Context to be
ready by default, now you can override this value in two ways:
-
Globally, by setting
org.apache.camel.test.blueprint.camelContextCreationTimeout
system property. -
Locally for each test, by overriding getCamelContextCreationTimeout method.
Adding services on startup
Since Camel 2.11.2/2.12.0
When using camel-test-blueprint
you may do unit tests which requires
using shared services which are not available during unit testing, but
only in the real OSGi container, for example a shared DataSource
.
To make it easier to register services on startup, such as a standalone
DataSource
or any other service, you can override the method
addServicesOnStartup
when your unit test class extends
CamelBlueprintTestSupport
.
In the example below we register a service
org.apache.camel.test.blueprint.MyService
using the name myService
having a property beer=Carlsberg
, as shown below:
@Override
protected void addServicesOnStartup(Map<String, KeyValueHolder<Object, Dictionary>> services) {
services.put("myService", asService(myService, "beer", "Carlsberg"));
}
The asService is a builder method that makes it easy to register a
service with a single property. If you need more properties you can use
the asService
method that takes a Dictionary
as argument. And if you
do not need any properties, then just pass in null
, eg:
services.put("myService", asService(myService, null));
This allows us to use the service by calling a method on it from a Camel Bean component in a route as shown:
<route>
<from uri="direct:start"/>
<to uri="bean:myService"/>
<to uri="mock:result"/>
</route>
Notice the bean endpoint uses the service name myService
which was the
name we registered the service as. You can also use the fully qualified
class name instead, which is more common with OSGi.
@Override
protected void addServicesOnStartup(Map<String, KeyValueHolder<Object, Dictionary>> services) {
services.put(MyService.class.getName(), asService(myService, "beer", "Carlsberg"));
}
And in the route we use the FQN name:
<route>
<from uri="direct:start"/>
<to uri="bean:org.apache.camel.test.blueprint.MyService"/>
<to uri="mock:result"/>
</route>
From Camel 2.16.0, an additional addServicesOnStartup
method is
available to be overridden making it ideal for when needing to specify
multiple services with the same interface.
@Override
protected void addServicesOnStartup(List<KeyValueHolder<String, KeyValueHolder<Object, Dictionary>>> services) {
Dictionary<String, String> dict1 = new Hashtable<String, String>();
dict1.put("osgi.jndi.service.name", "jdbc/db1");
Dictionary<String, String> dict2 = new Hashtable<String, String>();
dict2.put("osgi.jndi.service.name", "jdbc/db2");
services.add(asKeyValueService(javax.sql.DataSource.class.getName(), mockService1, dict1));
services.add(asKeyValueService(javax.sql.DataSource.class.getName(), mockService2, dict2));
}
The asKeyValueService
builder method can be used to construct the
necessary parameters to create the service. The method takes in the name
of the registered service, the object, and and a Dictionary
as
arguments.