Over a million developers have joined DZone.

OSGi : Junit Test Extender Using Fragment and BundleTracker

· Java Zone

Microservices! They are everywhere, or at least, the term is. When should you use a microservice architecture? What factors should be considered when making that decision? Do the benefits outweigh the costs? Why is everyone so excited about them, anyway?  Brought to you in partnership with IBM.

I-Introduction :

As Service tracker, the Osgi 4.2 release introduced "BundleTracker" which simplifies working with bundles and facilitate building extenders. In this article, we will try to write a simple JUnit test extender using fragments (to separate tests from source code). We will give to the user opportunities to automate the unit test just after or when the fragment bundle is installed, plus a console command to test all installed fragments or a specific one.

II- BundleTracker

We will use BundleTrackerCustomizer to track only Resolved Bundle state as fragments will not be at started state and to be sure that this fragment has a resolved parent. 
bundleTracker = new BundleTracker(context, Bundle.RESOLVED, testExtender);

where TestExtender
1 - implements BundleTrackerCustomizer
2- check if it is a test fragment
        private static final String TEST_HEADER = "Unit-Test";
public static final boolean isTestFragment(Bundle bundle) {
String header = bundle.getHeaders().get(TEST_HEADER) + "";
String fragment = bundle.getHeaders().get(org.osgi.framework.Constants.FRAGMENT_HOST) + "";
return (!"null".equals(header) && !"null".equals(fragment));
3- If yes, add (or update) it to map using it's bundle id.
 private Map bundles = Collections.synchronizedMap(new HashMap());
bundles.put(bundle.getBundleId(), bundle);

4- check if auto test is enabled :
 public static final boolean isAutoTestEnabled(Bundle bundle) {
return "true".equals(bundle.getHeaders().get(TEST_HEADER) + "");
if (isAutoTestEnabled(bundle)) {

III- Test

Let's define loadClass method to load class from bundle and getHostBundle to get the parent Bundle
public static final Class loadClass(String clazz, Bundle bundleHost) {
try {
Class loadClass = bundleHost.loadClass(clazz);
return loadClass;

} catch (Exception e) {
throw new RuntimeException(e);
 public static final Bundle getHostBundle(BundleContext context,Bundle bundle) {
String fragment = bundle.getHeaders().get(org.osgi.framework.Constants.FRAGMENT_HOST) + "";
Bundle[] bundles = context.getBundles();
for (Bundle ibundle : bundles) {
if (ibundle.getSymbolicName().equals(fragment)) {
return ibundle;
throw new RuntimeException();

loadClass and getHostBundle will be used to load all test class from fragment using hostBundle context!!!! (fragment will be loaded using it's host context loader) and try to load all class with Test suffix recursively.
 public static final List> getTestClass(BundleContext context,Bundle bundle) {
List> clazzs = new ArrayList>();
Enumeration entrs = bundle.findEntries("/", "*Test.class", true);
if (entrs == null || !entrs.hasMoreElements()) {
return Collections.EMPTY_LIST;
Bundle hostBundle = getHostBundle(context,bundle);
while (entrs.hasMoreElements()) {
URL e = (URL) entrs.nextElement();
String file = e.getFile();

String className = file.replaceAll("/", ".").replaceAll(".class", "").replaceFirst(".", "");
Class clazz = loadClass(className, hostBundle);
return clazzs;

for each loaded test Class we inspect it to find junit annotated methods :
public static final Test inspectClass(Class clazz) {
Test test = new Test();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {

if (method.isAnnotationPresent(org.junit.BeforeClass.class)) {
if (method.isAnnotationPresent(org.junit.AfterClass.class)) {
if (method.isAnnotationPresent(org.junit.Before.class)) {
if (method.isAnnotationPresent(org.junit.After.class)) {
if (method.isAnnotationPresent(org.junit.Test.class)) {
return test;
and then, emulate junit mechanism using reflexion :
  public static void testClass(Test testClass, Object object) {

try {
try {
if (testClass.getBeforeClass() != null) {
testClass.getBeforeClass().invoke(object, new Object[0]);

List tests = testClass.getTests();
for (Method method : tests) {
try {
if (testClass.getBefore() != null) {
testClass.getBefore().invoke(object, new Object[0]);
try {
method.invoke(object, new Object[0]);
System.out.println("Method : [ "+ method.getName()+" ] PASS " );
} catch (Exception ex) {
System.out.println("Method : [ "+ method.getName()+" ] ERROR " );
} finally {
if (testClass.getAfter() != null) {
testClass.getAfter().invoke(object, new Object[0]);
} finally {
if (testClass.getAfterClass() != null) {
testClass.getAfterClass().invoke(object, new Object[0]);

} catch (Exception ex) {

the object passed to this method is a new instance of class this is why don't forget ( DynamicImport-Package: *)
  for (Class clazz : testClazzs) {
try {
System.out.println("CLASS : ["+clazz.getName()+"]");
Test inspectClass = EClassUtils.inspectClass(clazz);
EClassUtils.testClass(inspectClass, clazz.newInstance());
} catch (Exception ex) {

testAll loops all registered test.
public void testAll() {
Set> entrySet = bundles.entrySet();
for (Entry entry : entrySet) {

IV- Console

to give the user opportunities to test specific fragment or do all test our activator register CommandProvider service with 3 methods starting (_) :
 public Object _test(CommandInterpreter intp) {
String nextArgument = intp.nextArgument();
return null;

public Object _testall(CommandInterpreter intp) {
return null;

public Object _helpTest(CommandInterpreter intp) {
String help = getHelp();
return null;

(and _helpTest and not -help to conserve equinox help too)
public String getHelp() {
StringBuilder buffer = new StringBuilder();
buffer.append("---Testing commands---\n\t");
buffer.append("test [bundle id] - test bundle fragment id\n\t");
buffer.append("testall - test all fragments\n\t");
buffer.append("help - Print this help\n");
return buffer.toString();


our fragment contains 2 class one is to be tested (OneTest):
import static org.junit.Assert.*;
public class OneTest {

public void echo() {

public void fail() {

with manifest headers :
Fragment-Host: com.jtunisie.osgi.client
Unit-Test: true

Output :

30      ACTIVE      com.jtunisie.osgi.test.extender_1.0.0.SNAPSHOT
31      ACTIVE      com.jtunisie.osgi.client_1.0.0.SNAPSHOT
32      RESOLVED    com.jtunisie.osgi.fragment.test_1.0.0.SNAPSHOT

osgi> test 32
Bundle : [32] : com.jtunisie.osgi.fragment.test
CLASS : [com.jtunisie.osgi.fragment.test.OneTest]
Method : [ fail ] ERROR
Method : [ echo ] PASS

conclusion :

Hope this is article help you to test your bundles using clean fragment. Project can be exported to 4.1 release using listeners but BundleTracker is very helpful .

source code is shared in kenai : http://kenai.com/projects/testosgifragment

Discover how the Watson team is further developing SDKs in Java, Node.js, Python, iOS, and Android to access these services and make programming easy. Brought to you in partnership with IBM.


Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}