Approaches for Testing OSGi Applications

  • Sling OSGi Mocks — very lightweight, emulates all core features of an OSGi container in-memory. Covers 90% of what is required.
  • OPS4J PAX Exam — integration tests, complicated and heavy-weight
  • Sling Launchpad with Testing Tools — heavy-weight, for complex scenarios beyond OSGi Mocks

Goals for OSGi Unit Tests

  • Startup/Teardown of OSGi environment for each test run
  • Allow parallel execution of unit tests
  • Support basic OSGi features and all Declarative Services features
  • Control which OSGi services should be used in the test context
  • Allow combination with Mockito mocks
  • Visualize code coverage in IDE and CI
  • Maximum execution speed!

OsgiContext — JUnit 5

@ExtendWith(OsgiContextExtension.class)
class MatrixServiceTest {

    private final OsgiContext context = new OsgiContext();

    @BeforeEach
    void setUp() {
        // setup test
    }
}

// Can combine with Mockito:
@ExtendWith(OsgiContextExtension.class)
@ExtendWith(MockitoExtension.class)
class MatrixServiceTest {
    private final OsgiContext context = new OsgiContext();
    // ...
}

// Context convenience methods:
// context.bundleContext()
// context.componentContext()
// context.getService(Class)
// context.getServices(Class, filter)

Register Declarative Services

@BeforeEach
void setUp() {
    // registerInjectActivateService:
    // 1. Injects all dependencies (register them beforehand)
    // 2. Activates the service
    // 3. Registers the service in OSGi service registry
    // 4. Deactivates when unit test completes
    underTest = context.registerInjectActivateService(
        new OracleServiceImpl());
}

// With service properties:
underTest = context.registerInjectActivateService(
    new OracleServiceImpl(),
    "prop1", "value1",
    "prop2", 55);

// Dynamic references and configuration changes are supported

Register Mocked Services

@ExtendWith(OsgiContextExtension.class)
@ExtendWith(MockitoExtension.class)
class SentinelServiceTest {

    private final OsgiContext context = new OsgiContext();

    @Mock
    private GatekeeperService gatekeeperService;

    @BeforeEach
    void setUp() {
        context.registerService(GatekeeperService.class,
            gatekeeperService);
        when(gatekeeperService.checkAccess(anyString()))
            .thenReturn(true);
    }
}

Built-in OSGi Services

OSGi Mock provides mock implementations of:

  • OSGi LogService — logs events to SLF4J/Console
  • OSGi EventAdmin — sending events with topics between components (whiteboard)
  • OSGi ConfigAdmin — publish configurations for services

Hints and Pitfalls

  • Register services in the correct dependency order (take care of hierarchy yourself)
  • IDE must support Maven build plugins to generate SCR metadata before executing tests
  • If you see "No OSGi SCR metadata found in classpath" — use Project → Clean to recompile
  • Bundle configuration from POM is ignored by OSGi Mocks
  • Use Infinitest plugin (Eclipse/IntelliJ) to run tests automatically on each change
  • Constantly check code coverage in your IDE