Software QA FYI - SQAFYI

OSGi Service Test Helper: ServiceRegistrationRule

By: Frank Appel

OSGi Service Tests can be an efficient means to avoid problems related to dangling service references. As promised in my post about writing simple service contribution verifications, this time I introduce a JUnit rule that assists in testing interactions between components.

OSGi Service Tests for Component Interaction

Assume we have a service that notifies related observers bound according to the whiteboard-pattern. Precisely we have a Service declaration and ServiceImpl as in the previous post. Additionaly we support ServiceListeners that should be notified on particular actions.

To represent such an action we broaden the service interface of our example with a method declaration called Service#execute():
1 public interface Service {
2 void execute();
3 }


Beside the implementation of this execute method the contribution class have to provide the capabilities to bind and unbind ServiceListener references:
01 public class ServiceImpl
02 implements Service
03 {
04 public void execute() {
05 [...]
06 }
07
08 public void bind( ServiceListener listener ) {
09 [...]
10 }
11
12 public void unbind( ServiceListener listener ) {
13 [...]
14 }
15 }


As notification destination the callback type ServiceListeners provides a method declaration called ServiceListener#executed():
1 public interface ServiceListener {
2 void executed();
3 }


To complete the setup we have to register the service component, which we do again via declarative services. Note the additional 0..n reference declaration:
01 <?xml version="1.0" encoding="UTF-8"?>
02 <scr:component
03 xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
04 immediate="true"
05 name="Implementation of Service API">
06 <implementation class="com.codeaffine.example.core.ServiceImpl"/>
07 <:service<
08 <provide interface="com.codeaffine.example.api.Service"/>
09 </service>
10 <reference
11 bind="bind"
12 unbind="unbind"
13 cardinality="0..n"
14 interface="com.codeaffine.example.api.ServiceListener"
15 name="ServiceListener"
16 policy="dynamic" />
17 </scr:component>


Now the question is: How can we test that un-/binding of a listener works correctly and notifications are dispatched as expected? The basic idea is to register a ServiceListener spy and trigger Service#execute on the actual service implementation.

The spy records calls to execute and allows to verify that binding and notification work as expected. Once we have ensured this, we can go on and deregister a primarily registered spy and verify that it is not notified about a subsequent action event. This makes sure unbinding works also as planned.

However the test fixture for this scenario usually needs a bit of OSGi boilerplate. To reduce the clutter I have written a little JUnit rule that eases service registration and automatically performs a service registry cleanup after each test run.

ServiceRegistrationRule

As every other JUnit TestRule the ServiceRegistrationRule has to be provided as a public field in our PDE test. Note how the rule uses a parameterized constructor given the class instance of the test case. This reference is used to get hold of an appropriate BundleContext for service de-/registration.

01 @Rule
02 public final ServiceRegistrationRule serviceRegistration
03 = new ServiceRegistrationRule( getClass() );
04
05 private ServiceListener listener;
06 private Service service;
07
08 @Before
09 public void setUp() {
10 service = collectServices( Service.class, ServiceImpl.class ).get( 0
);
11 listener = mock( ServiceListener.class );
12 }



The implicit test setup retrieves the registered service under test using the ServiceCollector I introduced in the last post. The listener DOC is created as spy using mockito. The first test scenario described above looks like this:
1 @Test
2 public void executeNotification() {
3 serviceRegistration.register( ServiceListener.class, listener );
4

5 service.execute();
6

7 verify( listener ).executed();
8 }


Pretty straight forward, isnít it?

Note that the ServiceRegistrationRule takes care of cleanup and removes the spy service from the service registry. To facilitate a test for the unbind scenario, the ruleís register method returns a handle to the service registration:
01 @Test

02 public void executeAfterListenerRemoval() {
03 Registration registration
04 = serviceRegistration.register( ServiceListener.class, listener );
05 registration.unregister();
06
07 service.execute();
08
09 verify( listener, never() ).executed();
10 }


Line five (registration.unregister()) removes the listener spy from the service registry. This triggers an unbind and the listener gets never invoked. Of course a real world scenario could add additional tests for multiple listener registrations, exception handling and the like, but I think the concept has been made clear.

Full article...


Other Resource

... to read more articles, visit http://sqa.fyicenter.com/art/

OSGi Service Test Helper: ServiceRegistrationRule