The JUnit4OSGi framework: a simple test framework for OSGi
JUnit4OSGi is a test framework executing JUnit tests on an OSGi runtime. JUnit4OSGi provides a JUnit++ environment specialized for OSGi, several runners and a maven plugin
Why JUnit4OSGi ?
Junit4OSGi is a framework allowing the execution of JUnit tests in an OSGi environment. It stems from the fact that testing applications on top on OSGi is quite complex compared to classic Java unitary tests
The goal of JUnit4OSGi is to provide the same mechanisms as unitary tests in an OSGi context. It allows using the JUnit concepts, although tests are run in an OSGi framework, using all of its distinctivenesses. The JUnit4OSGi bundle allows you to :
- Perform OSGi services tests.
- Test applications on different VMs, OSGi implementations.
- Test dynamism impact.
This pages describes also a tutorial. With the archive tutorial, a preconfigured version of Felix (with the test framework already installed) is provided.
Working principles

The goal of unitary tests in an OSGi context is to check that the bundles (the OSGi deployment units) to test are correctly deployed, that they expose the expected services and that these services work properly. Tests are placed in a bundle, which is deployed in the OSGi environment to test. Then, they can interact with the environment (more specifically bundles and services) to check that everything works well.
Getting JUnit4OSGi
The JUnit4OSGi framework is available from the Felix trunk in the iPOJO folder. the JUnit4OSGi framework and the different launchers are built when you compile Felix.
How to run test cases
Once tests have been deployed on the OSGi framework, there are several way to run the tests
- You can use the JUnit4OSGi immediate-runner, which run tests contained in all the test-bundles. The results are displayed in the framework console output.
- The JUnit4OSGi Felix Command (available only for the Apache Felix OSGi framework), allows you to run tests contained in a specific bundle. Test results are also displayed in the framework console output. The syntax of the command is very simple :
- To run tests contained in the bundle with the given id :{{
}}
- To run tests contained in all the test-bundles installed in the framework :
junit all
- The JUnit4OSGi Swing GUI lets you select the test cases and test suites to execute and shows you graphically the result of the tests. You can double-click on a test case result to show its details.

TestCase, TestSuite
A test case is an environment (made of conditions and variables) under which a tester will check that a requirement is satisfied. For JUnit, test cases are classes that define several test methods ; each test method tests an aspect of the targeted requirement. Test cases are often collected into test suites. A test suite aggregates several test cases (and even other test suites), including the notion of test hierarchy. Tests can be organized according to the different requirements they try to validate. The skeleton of a JUnit TestCase and TestSuite is shown just above :
/**
* The skeleton of a JUnit test case
*/
public class MyTestCase extends junit.framework.TestCase {
...
public void setUp() {
// Performs actions BEFORE running any test case.
}
public void testSomething() throws AnyException {
// A test method
...
assertTrue(myTest);
assertEquals(myValue, expectedValue);
...
}
public void testAnotherThing() {
// Another test method
...
}
public void tearDown() {
// Performs actions AFTER running all test cases.
}
}
|
/**
* The skeleton of a JUnit test suite
*/
public class MyTestSuite extends junit.framework.TestSuite {
/**
* The skeleton of a JUnit test suite
*/
public static Test suite() {
TestSuite suite = new TestSuite("The name of the test suite");
suite.addTestSuite(MyTestCase.class);
suite.addTestSuite(AnotherTestCase.class);
...
return suite;
}
}
|
First, tests methods are declared in the test case. Their name must begin with "test", so JUnit will execute them on demand. The test are expressed in terms of JUnit assertions ; the assert*() methods causes JUnit test failure if the given assertion is false. The setUp() and tearDown() methods perform specific actions before and after test cases are run. Then, the test suite collect various test cases. It must implement the suite() method that returns the global (and organized) test suite to JUnit.
OSGiTestCase and OSGiTestSuite
An OSGi test case, is a test case that runs in an OSGi context. OSGiTestCase is the class that all the OSGi test cases you write must extend. This class is a kind of bridge between the JUnit TestCase class and the OSGi environment. The only thing the OSGiTestCase class adds is the access to the bundle context of the bundle containing tests, and some utility methods, giving an easy access to other bundles and services registered in the OSGi framework.
The structure of an OSGiTestCase is exactly the same as a classic JUnit TestCase :
/**
* The structure of an OSGiTestCase
*/
public class MyOSGiTestCase extends OSGiTestCase {
public void setUp() {...}
public void testSomething() {
// You can access here the bundle context through
// the 'getContext()' method
getContext().getServiceReference(...);
...
}
public void testAnotherThing() {...}
...
public void tearDown() {...}
}
|
By extension, OSGi test suites are collections of OSGi test cases. But you can also add classic JUnit test cases inside your OSGiTestSuite. The skeleton of an OSGiTestSuite is globally the same as a TestSuite, except the fact that a reference to the bundle context is passed :
public class MyOSGiTestSuite {
/**
* This method returns the suite of tests to run.
*/
public static Test suite(BundleContext bc) {
OSGiTestSuite suite = new OSGiTestSuite("My OSGi test suite", bc);
suite.addTestSuite(MyFirstTest.class);
suite.addTestSuite(MySecondTest.class);
...
// Here, we add a sub test suite in this test suite.
suite.addTest(AnotherTestSuite.suite(bc));
...
return suite;
}
}
|
How to declare test suites
This section explains how to declare your test suites in order to expose them to the JUnit4OSGi bundle.
The written OSGi test suites must be declared by the bundle containing them. To do so, you define add the Test-Suite property in your bundle's header. The following snippets show you how to configure your bundle generation tool to add this property in the header. You can even declare test cases in it. The Junit4OSGi bundle will detect such an header in installed bundle (using the extender pattern) and execute contained tests on demand.
With the maven-bundle-plugin, add the following lines in your project's pom :
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
...
<extensions>true</extensions>
<configuration>
<instructions>
...
<!-- Declare here the test cases and test suites of your bundle -->
<Test-Suite>
a.package.MyFirstTestSuite,
yet.another.package.MySingleTestCase
...
</Test-Suite>
</instructions>
</configuration>
</plugin>
|
With the aQute Bnd Ant task, add the following lines in your project bnd file:
Test-Suite: a.package.MyFirstTestSuite, yet.another.package.MySingleTestCase, ...
|
Quick examples
The following examples show you how to perform unitary tests on your OSGi platform. The first example recovers the example given in the JUnit Cookbook, "bundlizes" it so tests can be run in an OSGi environment. None of the JUnit4OSGi specific features is used, but it shows how to adapt classic JUnit tests. The second example is more OSGi-oriented, and shows how a unitary test can access to the framework via its bundle context.
These examples can be downloaded here.
Bundles to deploy to use junit4osgi
If you don't use the archive, you can deploy the junit4osgi framework manually. Here is the list of the bundles to deploy and start:
- org.apache.felix.ipojo-1.2.0.jar: iPOJO Core bundle
- org.apache.felix.ipojo.handler.extender-1.2.0.jar: iPOJO Extender pattern handler
- org.apache.felix.ipojo.junit4osgi-1.1.0-SNAPSHOT.jar: the JUnit4OSGi framework
- org.apache.felix.ipojo.junit4osgi.felix-command-1.1.0-SNAPSHOT.jar: the command line junit4osgi runner
The remixed JUnit example
This example is a simple conversion of a classic JUnit example derived from the JUnit Cookbook. The test case and the test suite are shown to remind you JUnit principles.
package junit.example;
import junit.framework.TestCase;
import junit.money.Money;
public class SimpleTestCase extends TestCase {
private Money f12CHF;
private Money f14CHF;
public void setUp() {
f12CHF= new Money(12, "CHF");
f14CHF= new Money(14, "CHF");
}
public void testEquals() {
assertTrue(!f12CHF.equals(null));
assertEquals(f12CHF, f12CHF);
assertEquals(f12CHF, new Money(12, "CHF"));
assertTrue(!f12CHF.equals(f14CHF));
}
public void testSimpleAdd() {
Money expected= new Money(26, "CHF");
Money result= f12CHF.add(f14CHF);
assertTrue(expected.equals(result));
}
}
|
package junit.example;
import junit.framework.Test;
import junit.framework.TestSuite;
public class SimpleTestSuite {
public static Test suite() {
TestSuite suite = new TestSuite("Money Simple Test Suite");
suite.addTestSuite(SimpleTestCase.class);
return suite;
}
}
|
The following bnd file declares the test suite in the target bundle's header :
Private-Package: junit.money, junit.example
Test-Suite: junit.example.SimpleTestSuite
|
Once built, the bundle must be deployed in the provided Felix framework, and tests can be performed using the 'junit' command :
-> ps
START LEVEL 1
ID State Level Name
...
[ 12] [Active ] [ 1] Junit-Example (0)
...
-> junit 12
Executing [Money Simple Test Suite]
..
Time: 0
OK (2 tests)
->
|
As you can see above, all tests have been correctly executed !
An OSGi-based JUnit example
This example shows you how to interact with the OSGi framework within your tests. The test bundle provide a service (HelloService) and tests its work normally. To get the service reference of the HelloService, it uses the bundle context field of the OSGiTestCase class (named 'context') and interacts with it like any other OSGi bundle does.
package junit.example;
import junit.service.hello.HelloService;
import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
import org.osgi.framework.ServiceReference;
public class SimpleTestCase extends OSGiTestCase {
public void testHelloAvailability() {
ServiceReference ref = getContext().getServiceReference(HelloService.class.getName());
assertNotNull("Assert Availability", ref);
}
public void testHelloAvailability2() {
ServiceReference ref = getServiceReference(HelloService.class.getName(), null);
assertNotNull("Assert Availability", ref);
}
public void testHelloMessage() {
ServiceReference ref = getContext().getServiceReference(HelloService.class.getName());
assertNotNull("Assert Availability", ref);
HelloService hs = (HelloService) getContext().getService(ref);
String message = hs.getHelloMessage();
assertNotNull("Check the message existence", message);
assertEquals("Check the message", "hello", message);
}
public void testHelloMessage2() {
assertTrue("Check availability of the service",
isServiceAvailable(HelloService.class.getName()));
HelloService hs = (HelloService) getServiceObject(HelloService.class.getName(), null);
String message = hs.getHelloMessage();
assertNotNull("Check the message existence", message);
assertEquals("Check the message", "hello", message);
}
}
|
The performed tests give out the following results :
-> ps
START LEVEL 1
ID State Level Name
...
[ 17] [Active ] [ 1] Junit-OSGi-Example (0)
...
-> services 17
Junit-OSGi-Example (17) provides:
---------------------------------
objectClass = junit.service.hello.HelloService
service.id = 36
-> junit 17
Executing [Hello Service Test Suite]
..
Time: 0,015
OK (4 tests)
->
|
Utility methods description
The OSGiTestCase class provides some utility methods which eases the use of OSGi services and the interaction with iPOJO components. The description of these methods can be found afterwards.
On top of the presented (static) methods, you can find non-static methods which have access the local bundle context only.
OSGi specific methods
BundleContext getContext() : gives access to the OSGiTestCase bundle context.
Object getServiceObject(Bundle bundle, String itf, String filter) : this method returns the service object of a service provided by the specified bundle, offering the specified interface and matching the given filter.
Object[] getServiceObjects(Bundle bundle, String itf, String filter) : returns the service objects of the all the services provided by the specified bundle, offering the specified interface and matching the given filter.
ServiceReference getServiceReference(Bundle bundle, String itf, String filter) : returns the service reference of a service provided by the specified bundle, offering the specified interface and matching the given filter.
ServiceReference getServiceReferenceByPID(Bundle bundle, String itf, String pid) : returns the service reference of the service provided by the specified bundle, offering the specified interface and having the given persistent ID.
ServiceReference getServiceReferenceByName(Bundle bundle, String itf, String name) : returns the service reference of a service provided by the specified bundle, offering the specified interface and having the given name.
ServiceReference[] getServiceReferences(Bundle bundle, String itf, String filter) : returns the service reference of all the services provided in the specified bundle, offering the specified interface and matching the given filter.
boolean isServiceAvailable(String itf) : returns true if the service is available.
boolean isServiceAvailableByName(String itf, String name) : returns true if the service is available with the given name.
boolean isServiceAvailableByPID(String itf, String pid) : returns true if the service is available with the given pid.
These methods can be used directly in the OSGi Test Case as illustrated above.
It is easier to get service objects via the non-static getServiceObject() methods, as they
automatically release the service reference at the end of the test (tearDown method).
iPOJO specific methods
As JUnit4OSGi is part of the iPOJO project, it contains iPOJO specific utility methods, to help accessing factories and the creation of component instances.
To access to these methods, creates a IPOJOHelper object:
public class ATestCase extends OSGiTestCase {
IPOJOHelper helper = new IPOJOHelper(this);
}
|
With this object, you can easily retrieve data about instances, as well as recreated new instances, analyzing service contexts...
Moreover, if you create instances with the non-static methods (createComponentInstance(String, String, Dictionary), createComponentInstance(String) or
createComponentInstance(String, String), to dispose instances just call the helper.dispose() method. The created instances are automatically disposed.
Configuration Admin methods
Coming soon...
Executing test in a Maven build process
A maven plugin allows executing test written with junit4osgi automatically. The documentation of this plug-in is available here.
This plug-in also supports Cobertura, and so is able to report the code coverage of your tests. For further information read the Code coverage of OSGi applications article.
|