Thursday, April 17, 2008

Is OSGi the enemy of JUnit tests?

I wrote a set of JUnit(3.8.1) tests for the terminal. Originally those were normal unit-tests. To be able to test non public methods and non public classes, I put the tests into the same package but into a separate test plugin. I also added the test plugin as friend plugin of the packages I want to test. This works fine if I run the tests as normal JUnit tests. But if I run the same tests as JUnit Plug-in Tests I get java.lang.IllegalAccessError. The reason is simple: each OSGi bundle runs it's own class loader and therefore the classes appear not to be in the same package.

There are different solutions:

  • Make all methods and classes you want to test public (really bad idea)
  • Put the unit tests into the same plugin as your code and make the dependency to JUnit optional (not a good separation of concerns).
  • Only test public classes and methods (I think this is to restrictive and often to coarse grain)
  • Make your test plugin a fragment. One problem is that other plugins cannot access classes defined in fragments (as Patrick Paulin points out in a more detailed discussion about fragments in unit tests). Another problem is that plugin.xml in a fragment is ignored. And therefore you test plugin cannot contribute


I tried out turning a plugin into a fragment. It is as simple as adding adding a line following line to your MANIFEST.MF
Fragment-Host: org.eclipse.the.plugin.you.want.to.test
and removing the plugin you want to test from the required plugins. As long as your test plugin is not part of a bigger test case and it does not need to contribute extensions Patrick Paulin describes a solution for that using reflection, fragments are a good solution.

A good way to avoid having to use extensions (plugin.xml) in your test plugin is to use dependency injection for your classes.

But I think there should be a better way to write a test plugin that can access non public classes and members. I understand why the security concept of OSGi introduces those problems, but I am still looking for a solution for my JUnit tests.

Any ideas?