Execution of JUnit Tests in a Single-Sourced Application
September 24, 2013 | 3 min ReadOne strength of Eclipse is the possibility to use the same code on desktop clients as well as in web clients. The same application can run as an installed desktop application and in the web browser, with only few adjustments for both platforms. In our experience, about 80% to 90% of the code can run in both environments, if some guidelines are followed (i.e. no Singletons for data management).
Some code must be platform specific, for example for file handling or internationalization. While the desktop application should use the locale of the OS, the web application should use browser settings. The language in a web application potentially differs per session, while the language on a desktop is fairly static.
The usual procedure for handling such differences is a single-sourcing pattern that consists of different implementations for an abstract class or interface. The implementations reside in their respective fragments. Details and code samples can be found in the Single-Sourcing guide [1]. If you are new to single sourcing, see also how to single source with declarative services [2].
At runtime, only one fragment is present. OSGi takes care of putting the fragment in the same classloader, and the implementation is loaded with Class.forName()
.
Take note of the peculiar dependency directions with fragments. A fragment depends on its plug-in. Plug-ins can not depend on fragments. So, when a plain JUnit launch target calculates the classpath for a test in my.test.plugin
, the fragment is not there. Thus, the class loading fails.
In an i18ned application, many externalized strings may be on the execution path of a test, even if it does not care about the texts at all. The typical fallback for this is to run a PDE test, but PDE tests are a pain for execution time alone, and don’t get me started about set-up problems. We prefer to run plain JUnit tests whenever possible.
To make JUnit test execution possible with these preconditions, create a third implementation of the single-sourced class. Put it in some test utility plug-in, so that it is on the dependency path from the test plug-in. Now, if the IDE calculates the classpath, an implementation can be found and loaded.
Warning: Note that in an OSGi environment the single-sourced implementation of a fragment is loaded. If your tests rely on any specifics in the test implementation, make sure that your tests are always executed as plain JUnit test. This means, if your CI works with Maven/Tycho, you can do whatever you want. If your tests run with the Eclipse Test Framework [3], you will have 2 different implemenations for JUnit and CI tests.
What is your test setup in single-sourced applications?
[1] /about/contact-us/single-sourcing-guide-pdf-download/
[2] /blogs/2011/07/08/single-sourcing-with-declarative-services/
[3] https://wiki.eclipse.org/Platform-releng/Eclipse_Test_Framework