Использование декларативных сервисов OSGi в контексте теста JUnit - PullRequest
11 голосов
/ 23 августа 2011

Я пытаюсь выяснить, как реализовать тест интеграции нескольких пакетов в OSGi с использованием JUnit.

Под интеграционным тестом я имею в виду создание экземпляра подмножества пакетов для автоматической проверки функциональности в этой подсистеме.

Мы запускаем Equinox и используем Eclipse в качестве цепочки инструментов. Eclipse предлагает опцию «Run as JUnit Plug-in», которая поднимает платформу OSGi и создает экземпляры пакетов конфигурации, так что я думаю, что это путь, по которому нужно следовать, но я не нахожу способ внедрить ссылки DS в мои тесты. Я видел использование ServiceTracker в качестве программного средства для доступа к различным пакетам услуг, но это лучше, чем иметь DS, не так ли?

Я только начинаю работать с OSGI, поэтому я полагаю, что мне не хватает какой-то части головоломки, которая позволила бы мне собрать мои тесты из нескольких пакетов.

Есть идеи?

Спасибо, Джерард.

* РЕДАКТИРОВАТЬ: РЕШЕНИЕ *

После более подробного изучения этой проблемы я, наконец, выяснил, как внедрить эти тесты интеграции с несколькими пакетами с помощью функции подключаемого модуля JUnit:

Чтобы внедрение динамических служб работало, необходимо создать файл определения службы, в котором должны быть объявлены внедренные зависимости, как это обычно делается при работе с DS. Этот файл (обычно) находится в каталоге OSGI-INF/. например OSGI-INF/service.xml

service.xml должен объявить необходимые зависимости для этого теста, но не предлагает собственную службу:

service.xml
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="MyTest" activate="startup" deactivate="shutdown">

   <implementation class="com.test.functionaltest.MyTester"/>
   <reference name="OtherService" interface="com.product.service.FooService" policy="static" cardinality="1..1" bind="onServiceUp" unbind="onServiceDown"/>

</scr:component>

Это будет указывать DS вводить зависимость от FooService, используя объявленный метод onServiceUp. onServiceDown должен быть реализован так, как он вызывается во время фазы выключения OSGi после запуска тестов.

com.test.functionaltest.MyTester содержит методы тестирования, которые должны быть выполнены, следуя типичным практикам JUnit.

Здесь все по книге. Тем не менее, если Junit запущен, он выдаст исключение NullPointerException при доступе к ссылке на FooService. Причина этого заключается в том, что платформа OSGi находится в состоянии гонки с контекстом выполнения тестов JUnit, и обычно тестовый запуск Junit выигрывает эту гонку, выполняя тесты до введения ссылки на требуемую службу.

Чтобы разрешить эту ситуацию, необходимо выполнить тест Junit, чтобы дождаться, пока среда выполнения OSGi выполнит свою работу. Я решил эту проблему с помощью CountDownLatch, который инициализируется количеством зависимых сервисов, необходимых в тесте. Затем каждый метод внедрения зависимостей ведет обратный отсчет, и когда все они будут выполнены, тест начнется. Код выглядит так:

private static CountDownLatch dependencyLatch = new CountDownLatch(1);// 1 = number of dependencies required    
static FooService  fooService = null;   
public void onFooServiceUp(FooService service) {
  fooService = service;
  dependencyLatch.countDown();
}

Обратите внимание, что ссылка fooService должна быть статической, чтобы разрешить разделение ссылки на службу между контекстами выполнения OSGi и JUnit. CountDownLatch предоставляет механизм синхронизации высокого уровня для безопасной публикации этой общей ссылки.

Затем перед выполнением теста необходимо добавить проверку зависимостей:

@Before
public void dependencyCheck() {
  // Wait for OSGi dependencies
    try {
      dependencyLatch.await(10, TimeUnit.SECONDS); 
      // Dependencies fulfilled
    } catch (InterruptedException ex)  {
      fail("OSGi dependencies unfulfilled");
    }
}

Таким образом, инфраструктура Junit ожидает, пока служба OSGi DS не введет зависимости, или произойдет сбой по истечении времени ожидания.

Мне потребовалось довольно много времени, чтобы полностью понять это. Я надеюсь, что в будущем это избавит коллег от программистов.

Ответы [ 5 ]

6 голосов
/ 12 июня 2012

* РЕДАКТИРОВАТЬ: РЕШЕНИЕ *

После более глубокого изучения этой проблемы я наконец-то понял, как внедрить эти тесты интеграции с несколькими пакетами с помощью функции подключаемого модуля JUnit:

Чтобы внедрение динамических служб работало, необходимо создать файл определения службы, в котором должны быть объявлены внедренные зависимости, как это обычно делается при работе с DS. Этот файл (обычно) находится в каталоге OSGI-INF/. например OSGI-INF/service.xml

service.xml должен объявить необходимые зависимости для этого теста, но не предлагает собственную службу:

service.xml
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="MyTest" activate="startup" deactivate="shutdown">

   <implementation class="com.test.functionaltest.MyTester"/>
   <reference name="OtherService" interface="com.product.service.FooService" policy="static" cardinality="1..1" bind="onServiceUp" unbind="onServiceDown"/>

</scr:component>

Это будет указывать DS вводить зависимость от FooService, используя объявленный метод onServiceUp. onServiceDown должен быть реализован так, как он вызывается во время фазы выключения OSGi после запуска тестов.

com.test.functionaltest.MyTester содержит методы тестирования, которые должны быть выполнены в соответствии с типичными практиками JUnit.

Здесь все по книге. Тем не менее, если Junit запущен, он выдаст исключение NullPointerException при доступе к ссылке на FooService. Причина этого заключается в том, что платформа OSGi находится в состоянии гонки с контекстом выполнения тестов JUnit, и обычно тестовый запуск Junit выигрывает эту гонку, выполняя тесты до введения ссылки на требуемую службу.

Чтобы разрешить эту ситуацию, необходимо выполнить тест Junit, чтобы дождаться, пока среда выполнения OSGi выполнит свою работу. Я решил эту проблему с помощью CountDownLatch, который инициализируется количеством зависимых сервисов, необходимых в тесте. Затем каждый метод внедрения зависимостей ведет обратный отсчет, и когда все они будут выполнены, тест начнется. Код выглядит так:

private static CountDownLatch dependencyLatch = new CountDownLatch(1);// 1 = number of dependencies required    
static FooService  fooService = null;   
public void onFooServiceUp(FooService service) {
  fooService = service;
  dependencyLatch.countDown();
}

Обратите внимание, что ссылка fooService должна быть статической, чтобы разрешить разделение ссылки на службу между контекстами выполнения OSGi и JUnit. CountDownLatch предоставляет механизм синхронизации высокого уровня для безопасной публикации этой общей ссылки.

Затем перед выполнением теста необходимо добавить проверку зависимостей:

@Before
public void dependencyCheck() {
  // Wait for OSGi dependencies
    try {
      dependencyLatch.await(10, TimeUnit.SECONDS); 
      // Dependencies fulfilled
    } catch (InterruptedException ex)  {
      fail("OSGi dependencies unfulfilled");
    }
}

Таким образом, инфраструктура Junit ожидает, пока служба OSGi DS не введет зависимости, или произойдет сбой по истечении времени ожидания.

Мне потребовалось довольно много времени, чтобы полностью понять это. Я надеюсь, что в будущем это избавит коллег от программистов.

1 голос
/ 24 августа 2011

Вы настраиваете его, используя вкладки в конфигурации запуска.

Итак, щелкните правой кнопкой мыши, выберите «запустить как», выберите «запустить конфигурации ...», дважды щелкните «Тест подключаемого модуля JUnit»,затем добавьте свои зависимости на вкладке плагинов - почти так же, как и в обычном лаунчере

Некоторые ссылки: http://publib.boulder.ibm.com/infocenter/ratdevz/v8r0/index.jsp?topic=/org.eclipse.pde.doc.user/guide/tools/launchers/junit_launcher.htm и http://publib.boulder.ibm.com/infocenter/ratdevz/v8r0/index.jsp?topic=/org.eclipse.pde.doc.user/guide/tools/launchers/junit_main.htm

1 голос
/ 08 ноября 2011

Полагаю, было бы немного чище овладеть org.apache.felix.scr.ScrService и активно ждать, пока компонент станет ACTIVE. Этот интерфейс реализован как равноденствием, так и Феликсом.

Java doc и Использование API .

1 голос
/ 24 августа 2011

Я не знаком с инструментами Eclipse, о которых вы упомянули, но мы успешно используем Pax Exam для интеграционного тестирования в Apache Sling . Если вы знакомы с Maven, POM по адресу https://svn.apache.org/repos/asf/sling/trunk/installer/it/pom.xml может помочь вам начать работу, и https://github.com/tonit/Learn-PaxExam также выглядит хорошей отправной точкой.

Инструменты тестирования Sling также могут помочь в этом контексте, позволяя пакетам добавлять тесты JUnit в среду OSGi во время выполнения, что полезно, если ваш проект генерирует исполняемый файл jar, который можно использовать для тестирования.

0 голосов
/ 10 января 2017

Я думаю, что в приведенном выше решении CountDownLatch не требуется.

Проблема в том, что JUnit в контексте DS создает экземпляр класса JUnitTest каждый для своего собственного.Сначала DS Context создает экземпляр вашего класса JUnitTest и вызывает привязку onFooServiceUp для FooService, но после этого JUnit создает свой собственный класс JUnitTest, не вызывая метод привязки onFooServiceUp.В этом случае FooService в JUnitTest недоступен.

Если вы объявляете FooService как статический (как вы это сделали) и присваиваете в методе onFooServiceUp, вам не нужна конструкция с CountDownLatch.

...