Home » Java » Enterprise Java » OSGi Service Test Helper: ServiceRegistrationRule

About Rudiger Herrmann

OSGi Service Test Helper: ServiceRegistrationRule

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():

public interface Service {
  void execute();
}

Beside the implementation of this execute method the contribution class have to provide the capabilities to bind and unbind ServiceListener references:

public class ServiceImpl
  implements Service
{
  public void execute() {
    [...]
  }

  public void bind( ServiceListener listener ) {
    [...]
  }

  public void unbind( ServiceListener listener ) {
    [...]
  }
}

As notification destination the callback type ServiceListeners provides a method declaration called ServiceListener#executed():

public interface ServiceListener {
  void executed();
}

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:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component
  xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
  immediate="true" 
  name="Implementation of Service API">
  <implementation class="com.codeaffine.example.core.ServiceImpl"/>
  <service<
    <provide interface="com.codeaffine.example.api.Service"/>
  </service>
  <reference 
    bind="bind" 
    unbind="unbind"
    cardinality="0..n"
    interface="com.codeaffine.example.api.ServiceListener"
    name="ServiceListener"
    policy="dynamic" />
</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.

@Rule
public final ServiceRegistrationRule serviceRegistration
  = new ServiceRegistrationRule( getClass() );

private ServiceListener listener;
private Service service;

@Before
public void setUp() {
  service = collectServices( Service.class, ServiceImpl.class ).get( 0 );
  listener = mock( ServiceListener.class );
}

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:

@Test
public void executeNotification() {
  serviceRegistration.register( ServiceListener.class, listener );

  service.execute();

  verify( listener ).executed();
}

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:

@Test
public void executeAfterListenerRemoval() {
  Registration registration
    = serviceRegistration.register( ServiceListener.class, listener );
  registration.unregister();

  service.execute();

  verify( listener, never() ).executed();
}

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.

Conclusion

So far the ServiceRegistrationRule proves itself quite useful in our current project. It reduces boilerplate significantly and makes the tests cleaner and increases readability. The class is part of the com.codeaffine.osgi.test.util feature of the Xiliary P2 repository: http://fappel.github.io/xiliary

In case you want to have a look at the code or file an issue you might also have a look at the Xiliary GitHub project: https://github.com/fappel/xiliary

For everything else feel free to use the commenting section below. In a followup I will explain how to setup a maven-tycho build with integrated PDE-Tests as those described above. This is somewhat tricky as tycho does not allow to access the bundles built by the current reactor, so stay tuned..

Reference: OSGi Service Test Helper: ServiceRegistrationRule from our JCG partner Rudiger Herrmann at the Code Affine blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

Receive Java & Developer job alerts in your Area

I have read and agree to the terms & conditions

 

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments