Based on the anwser of @dasblinkenlight and this anwser I came up with an implementation for my use case that I'd like to share.
I use the ServiceProviderPattern (difference API and SPI) for classes that implement the interface IImporterService
. If a new implementation of the interface is developed, only a configuration file in META-INF/services/ needs to be altered to register the implementation.
The file in META-INF/services/ is named after the fully qualified class name of the service interface (IImporterService
), e.g.
de.myapp.importer.IImporterService
This file contains a list of casses that implement IImporterService
, e.g.
de.myapp.importer.impl.OfficeOpenXMLImporter
The factory class ImporterFactory
provides clients with concrete implementations of the interface.
The ImporterFactory
returns a list of all implementations of the interface, registered via the ServiceProviderPattern. The setUp()
method ensures that a new instance is used for each test case.
@RunWith(Parameterized.class)
public class IImporterServiceTest {
public IImporterService service;
public IImporterServiceTest(IImporterService service) {
this.service = service;
}
@Parameters
public static List<IImporterService> instancesToTest() {
return ImporterFactory.INSTANCE.getImplementations();
}
@Before
public void setUp() throws Exception {
this.service = this.service.getClass().newInstance();
}
@Test
public void testRead() {
}
}
The ImporterFactory.INSTANCE.getImplementations()
method looks like the following:
public List<IImporterService> getImplementations() {
return (List<IImporterService>) GenericServiceLoader.INSTANCE.locateAll(IImporterService.class);
}