Saturday, 16 March 2013

OSGi integration tests with Bndtools and OSGi assertions library

Table of Contents

  1. Introduction
  2. Create an Integration Test project
  3. Installing external artifacts
  4. Add build dependencies
  5. Write integration tests
  6. Execute integration tests

1. Introduction


This tutorial shows you how to create OSGi integration tests with Bndtools and OSGi Assertions library. The tutorial is a continuation of the original Bndtools Tutorial.

2. Create an Integration Test project


Before start with Integration tests project please check that you finished Bndtools Tutorial and projects org.example.api and org.example.impls are created.

1. From the File menu, select New->Bndtools OSGi Project.
2. Name project org.example.it

3. Select "Integration Testing" project template

4. Edit org.example.tests.ExampleTest class to assert BundleContext
package org.example.tests;

import junit.framework.TestCase;

import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;

public class ExampleTest extends TestCase {

    private final BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();

    public void testExample() throws Exception {
        assertNotNull(context);
    }
}
5. Right-click on org.example.it project. Run As->Bnd OSGi Test Launcher (JUnit)



3. Installing external artifacts


Now we have to install OSGi Assertions library and dependencies into local repository.
1. Select Local Repository from the list and click Add Bundles to Repository

2. Click Add Exernal JARs... and copy-paste links to artifacts:
- org.apache.servicemix.bundles.junit-4.9_2.jar
- org.knowhowlab.osgi.testing.utils-1.1.0.jar
- org.knowhowlab.osgi.testing.assertions-1.1.0.jar




4. Add build dependencies


Open org.example.test Build tab and add dependencies:
- org.example.api
- org.knowhowlab.osgi.testing.utils
- org.knowhowlab.osgi.testing.assertions
- replace junit.osgi with org.apache.servicemix.bundles.junit (to support JUnit 4.x)



5. Write integration tests


Extend ExampleTest with JUnit 4 tests and OSGi Assertions
package org.example.tests;

import java.util.concurrent.TimeUnit;

import org.example.api.Greeting;
import org.junit.Test;
import org.osgi.framework.Bundle;

import static org.knowhowlab.osgi.testing.assertions.ServiceAssert.*;
import static org.knowhowlab.osgi.testing.assertions.BundleAssert.*;
import static org.knowhowlab.osgi.testing.utils.BundleUtils.*;

public class ExampleTest {

 @Test
    public void testGreetingService() throws Exception {
        assertServiceAvailable(Greeting.class);
    }

 @Test
    public void testGreetingProvider() throws Exception {
        assertBundleState(Bundle.ACTIVE, "org.example.impls.provider");
        
        assertServiceAvailable(Greeting.class);
        
        findBundle(getBundleContext(), "org.example.impls.provider").stop();

        assertServiceUnavailable(Greeting.class, 1, TimeUnit.SECONDS);
    }
}

6. Execute integration tests


1. Update Run Requirements


2. Update Source tab and define manually test case class


3. Right-click on org.example.it project. Run As->Bnd OSGi Test Launcher (JUnit)

11 comments:

  1. Hello, Thanks a lot for your tutorial! concerning to the Bndtool it's really interesting in the eclipse environment.. but I also want to reuse bnd.bnd (generated by Bndtool) with maven build, could you please give some advice on this ? thanks in advance!

    Kind regards,
    Thanh Le

    ReplyDelete
    Replies
    1. Hi Thanh,

      you can use maven-antrun-plugin to use bndtools ant tasks from maven. Check here for ant samples: http://wiki.osgi.org/wiki/BndtoolsAntEclipseToolchain

      Delete
    2. Thanks a lot for your answer! this really help me! a further question :) is it possible to execute a *.bndrun from console?

      Delete
    3. you can find complete manual for bnd tool that is a core of Bndtools IDE here: http://www.aqute.biz/Bnd/. Regarding your question: check pages: http://www.aqute.biz/Bnd/Ant and http://www.aqute.biz/Bnd/Projects

      Delete
  2. Thanks for this tutorial.

    It works fine for me until "6.Execute integration tests"

    The figure in step 1 is confusing to me.

    I did not create any run.bnd inside my org.example.it bundle. , but added the bundles depicted in the "Run Bundles" section (see figure) in the "Run" tab of my bnd.bnd.

    Then I followed step 2 and 3, i.e. the tests run without any problems.

    Could you please clarify?

    ReplyDelete
    Replies
    1. Hi Amro,

      thank you for your feedback.

      With Bndtools 2.0 it's possible to run bundles with *.bnd files. Since 2.1 it's recommended to use only *.bndrun files for this: http://bndtools.org/whatsnew.html#important-notes

      Delete
    2. Alright. Thanks for your quick reply.

      Delete
  3. To also test the functionality of the Greeting service in the integration test you could extend the class, please see my snippet below. I know for testing the actual functionality unit tests are more appropriate, but if you want to test a consumer bundle, this might help.

    --- code start ---

    package org.example.tests;

    import static org.knowhowlab.osgi.testing.assertions.BundleAssert.assertBundleState;
    import static org.knowhowlab.osgi.testing.assertions.OSGiAssert.getBundleContext;
    import static org.knowhowlab.osgi.testing.assertions.ServiceAssert.assertServiceAvailable;
    import static org.knowhowlab.osgi.testing.assertions.ServiceAssert.assertServiceUnavailable;
    import static org.knowhowlab.osgi.testing.utils.BundleUtils.findBundle;

    import java.util.concurrent.TimeUnit;

    import org.example.api.Greeting;
    import org.junit.Test;
    import org.osgi.framework.Bundle;
    import org.osgi.framework.BundleContext;
    import org.osgi.framework.ServiceReference;

    public class ExampleTest {

    private Greeting greetingSvc;

    @Test
    public void testGreetingService() throws Exception {
    assertServiceAvailable(Greeting.class);
    }

    @Test
    //put this method for testing below testStoppingProvider() and the test fails due to null pointer exception
    public void testHello(){
    initGreetingSvc();

    String result = greetingSvc.sayHello("Bob");

    org.junit.Assert.assertEquals("Hello Bob", result);
    }

    @Test
    public void testStoppingProvider() throws Exception {
    assertBundleState(Bundle.ACTIVE, "org.example.impls.provider");

    findBundle(getBundleContext(), "org.example.impls.provider").stop();

    assertServiceUnavailable(Greeting.class, 1, TimeUnit.SECONDS);
    }

    private void initGreetingSvc(){

    BundleContext context = getBundleContext();

    ServiceReference ref = context.getServiceReference(Greeting.class.getName());

    greetingSvc = (Greeting) context.getService(ref);
    }

    }

    --- code end ---

    ReplyDelete
  4. Could we extend the example to test the functionality when the service is retrieved?

    Here is my extended code:

    package org.example.tests;

    import static org.knowhowlab.osgi.testing.assertions.BundleAssert.assertBundleState;
    import static org.knowhowlab.osgi.testing.assertions.OSGiAssert.getBundleContext;
    import static org.knowhowlab.osgi.testing.assertions.ServiceAssert.assertServiceAvailable;
    import static org.knowhowlab.osgi.testing.assertions.ServiceAssert.assertServiceUnavailable;
    import static org.knowhowlab.osgi.testing.utils.BundleUtils.findBundle;

    import java.util.concurrent.TimeUnit;

    import org.example.api.Greeting;
    import org.junit.Test;
    import org.osgi.framework.Bundle;
    import org.osgi.framework.BundleContext;
    import org.osgi.framework.ServiceReference;

    public class ExampleTest {

    private Greeting greetingSvc;

    @Test
    public void testGreetingService() throws Exception {
    assertServiceAvailable(Greeting.class);
    }

    @Test
    //put this method for testing below testStoppingProvider() and the test fails due to null pointer exception
    public void testHello(){
    initGreetingSvc();

    String result = greetingSvc.sayHello("Bob");

    org.junit.Assert.assertEquals("Hello Bob", result);
    }

    @Test
    public void testStoppingProvider() throws Exception {
    assertBundleState(Bundle.ACTIVE, "org.example.impls.provider");

    findBundle(getBundleContext(), "org.example.impls.provider").stop();

    assertServiceUnavailable(Greeting.class, 1, TimeUnit.SECONDS);
    }

    private void initGreetingSvc(){

    BundleContext context = getBundleContext();

    ServiceReference ref = context.getServiceReference(Greeting.class.getName());

    greetingSvc = (Greeting) context.getService(ref);
    }

    }

    ReplyDelete
    Replies
    1. Hi Amro,

      thank you for your code. You've already extended the example with your comment :)

      Delete