Introduction

The Amdatu Testing project provides static utilities to simplify OSGi service integration tests. It currently supports the following features:

  • Inject service references automatically to your test class

  • Configure services and service factories using ConfigurationAdmin

  • Register services as part of the test setup

Additonal testing support is provided by other Amdatu projects. Projects providing additional testing support:

  • Amdatu Mongodb

  • Amdatu Web

For more information about test support provides by thees project see the documentation of these projects.

How to use

Service injection

Test configuration should be done in your test’s setup method by invoking TestConfigurator.configure(this) followed by adding components and configuration. The apply() method should be called after all steps have been specified, to actually apply the configuration to the test case and create the test context. The API to create dependencies stays very close to the Dependency Manager API. The test context should be cleaned up on tear down by calling TestConfigurator.cleanUp(this).

The example below demonstrates how to inject the Example service in our test case. The full example can be found on BitBucket.

ExampleTest.java
package org.amdatu.testing.example.test;

import static org.junit.Assert.assertEquals;

import org.amdatu.testing.configurator.TestConfigurator;
import org.amdatu.testing.example.Example;
import org.junit.Before;
import org.junit.Test;
import org.junit.After;

public class ExampleTest {

    private volatile Example serviceToTest;

    @Before
    public void setup() {
        TestConfigurator.configure(this)
            .add(TestConfigurator.createServiceDependency()
                .setService(Example.class)
                .setRequired(true))
            .apply();
    }

    @After
    public void after() {
        TestConfigurator.cleanUp(this);
    }

    @Test
    public void test() {
        String hello = serviceToTest.hello();
        assertEquals("Hello from org.amdatu.testing.example", hello);
    }

}

Running tests

Integration tests live in their own project, because they will run as a real bundle in an OSGi framework while executing the tests. The bnd.bnd file should contain a run configuration that consists of all the bundles required to run the bundles that are being tested, plus junit, and additional testing libraries (such as Amdatu Testing). To run tests you use the standard Bnd integration testing support, for this we need to add a Test-Cases header. This header is by Bnd to determine which tests it should run.

bnd.bnd
-buildpath: \
	org.amdatu.testing.configurator;version=latest,\
	org.amdatu.testing.example;version=latest,\
	org.apache.servicemix.bundles.junit

-runbundles: \
	org.apache.servicemix.bundles.junit,\
	org.mockito.mockito-core,\
	org.objenesis,\
	net.bytebuddy.byte-buddy,\
	net.bytebuddy.byte-buddy-agent,\
	org.amdatu.testing.configurator;version=latest,\
	org.amdatu.testing.example;version=latest

-runfeatures: base
-runfw: org.apache.felix.framework

Test-Cases:  \
	org.amdatu.testing.example.test.ExampleTest
Private-Package:  \
	org.amdatu.testing.example.test

Amdatu Blueprint provides features and project templates that make it easier to setup a new test.

Specifying a service filter

It is sometimes required to specify a service dependency with a filter. This can be done easily by passing an additional parameter to the createServiceDependency() method as follows:

@Before
public void setup() {
    TestConfigurator.configure(this)
        .add(TestConfigurator.createServiceDependency()
            .setService(Example.class, "(someKey=someValue)")
            .setRequired(true))
        .apply();
}

Configuring components

Some components rely on Configuration Admin to be configured. This can be easily done using the TestConfigurator using the createConfiguration method.

Example.java
package org.amdatu.testing.example.test;

import static org.junit.Assert.assertEquals;

import org.amdatu.testing.configurator.TestConfigurator;
import org.amdatu.testing.example.Example;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class ExampleConfigurationTest {

    private volatile Example serviceToTest;

    @Before
    public void setup() throws InterruptedException {
        TestConfigurator.configure(this)
            .add(TestConfigurator.createServiceDependency()
                .setService(Example.class)
                .setRequired(true))
            .add(TestConfigurator.createConfiguration("org.amdatu.testing.example")
                .set("message", "Hi")
                .setSynchronousDelivery(true))
            .apply();
    }

    @After
    public void after() {
        TestConfigurator.cleanUp(this);
    }

    @Test
    public void test() {
        String hello = serviceToTest.hello();
        assertEquals("Hi from org.amdatu.testing.example", hello);
    }

}

Because Configuration Admin works asynchronously, you have to be sure that the component is configured before you start your test. Especially with optional configurations this can be a problem.

The TestConfigurator supports synchronous delivery of the configuration to work around this problem using the ServiceConfigurator.setSynchronousDelivery method. When using this the ConfigurationAdmin service is bypassed and the configuration is applied to the ManagedService directly.

Registering services

It is sometimes required to define a new OSGi component as part of the test setup, for example for mocking some services. Here is an example demonstrating how to create a new component and specify its dependencies:

@Before
public void setup() {
    TestConfigurator.configure(this)
        .add(TestConfigurator.createComponent()
            .setInterface(MyService.class)
            .setImplementation(myServiceMock))
        .apply();
}

Providing groups of reusable configuration steps

It’s not uncommon to have multiple tests in your project performing rather similar configurations on setup. For example defining database configurations. Amdatu-testing lets you conveniently wrap a bunch of configuration steps and reuse them throughout your project. Below is an example demonstrating how to create such a reusable configuration.

TestUtils.java
class TestUtils {
    public static ConfigurationSteps reusableConfig() {
        return ConfigurationSteps.create()
            .add(createServiceDependency()
                .setService(Example.class)
                .setRequired(true));
    }
}

These reusable configuration steps can now be used like demonstrated below.

@Before
public void setup() {
    TestConfigurator.configure(this)
        .add(TestUtils.reusableConfig())
        .apply();
}

Components

Amdatu Testing provides the following static testing utility components:

Bundle

Required

Description

org.amdatu.testing.configurator

yes

Used to configure and inject services in test setup

Dependencies

The following table is an overview of the required and optional dependencies for Amdatu Testing:

Bundle

Required

Description

org.apache.felix.dependencymanager

yes

Apache Felix Dependency Manager is used internally by all Amdatu components

OSGi ConfigurationAdmin service (e.g. Apache Felix ConfigAdmin)

yes

Used to configure the services which are going to be tested

OSGi LogService (e.g. Apache Felix LogService)

no

Used to log output

Resources