Сервисные тесты OSGi могут быть эффективным средством, чтобы избежать проблем, связанных с висящими ссылками на сервисы. Как и было обещано в моем посте о написании простых проверок вклада сервисов , на этот раз я ввожу правило JUnit, которое помогает тестировать взаимодействия между компонентами.
Сервисные тесты OSGi для взаимодействия компонентов
Предположим, у нас есть сервис, который уведомляет связанных наблюдателей, привязанных по шаблону доски . Именно у нас есть Service и ServiceImpl как в предыдущем посте. Кроме того, мы поддерживаем ServiceListener который должен быть уведомлен о конкретных действиях.
Чтобы представить такое действие, мы расширили интерфейс службы нашего примера объявлением метода Service#execute() :
|
1
2
3
|
public interface Service { void execute();} |
Помимо реализации этого метода execute класс вклада должен предоставлять возможности для привязки и отмены привязки ссылок ServiceListener :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public class ServiceImpl implements Service{ public void execute() { [...] } public void bind( ServiceListener listener ) { [...] } public void unbind( ServiceListener listener ) { [...] }} |
В качестве пункта назначения уведомления тип обратного вызова ServiceListener s предоставляет объявление метода с именем ServiceListener#executed() :
|
1
2
3
|
public interface ServiceListener { void executed();} |
Для завершения настройки нам необходимо зарегистрировать сервисный компонент, что мы снова делаем через декларативные сервисы . Обратите внимание на дополнительное объявление 0..n:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
<?xml version="1.0" encoding="UTF-8"?><scr:component 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> |
Теперь возникает вопрос: как мы можем проверить, что отмена / привязка слушателя работает правильно и уведомления отправляются, как и ожидалось? Основная идея состоит в том, чтобы зарегистрировать шпион ServiceListener и инициировать выполнение Service#execute на фактической реализации сервиса.
Шпион записывает вызовы для execute и позволяет убедиться, что привязка и уведомление работают должным образом. Убедившись в этом, мы можем продолжить и отменить регистрацию в основном зарегистрированного шпиона и убедиться, что он не уведомлен о последующем событии действия. Это гарантирует, что открепление работает также, как запланировано.
Однако тестовое устройство для этого сценария, как правило, нуждается в небольшом шаблоне OSGi. Чтобы уменьшить беспорядок, я написал небольшое правило JUnit, которое облегчает регистрацию служб и автоматически выполняет очистку реестра служб после каждого запуска теста.
ServiceRegistrationRule
Как и любая другая JUnit TestRule должна быть предоставлена как открытое поле в нашем тесте PDE . Обратите внимание, как правило использует параметризованный конструктор для данного экземпляра класса тестового примера. Эта ссылка используется для получения соответствующего BundleContext для удаления / регистрации услуги.
|
01
02
03
04
05
06
07
08
09
10
11
12
|
@Rulepublic final ServiceRegistrationRule serviceRegistration = new ServiceRegistrationRule( getClass() );private ServiceListener listener;private Service service;@Beforepublic void setUp() { service = collectServices( Service.class, ServiceImpl.class ).get( 0 ); listener = mock( ServiceListener.class );} |
Установка неявного теста извлекает зарегистрированный тестируемый сервис, используя ServiceCollector я представил в последнем посте . DOC слушателя создается как шпион с использованием mockito . Первый описанный выше сценарий тестирования выглядит следующим образом:
|
1
2
3
4
5
6
7
8
|
@Testpublic void executeNotification() { serviceRegistration.register( ServiceListener.class, listener ); service.execute(); verify( listener ).executed();} |
Довольно прямо, не так ли?
Обратите внимание, что ServiceRegistrationRule заботится об очистке и удаляет шпионскую службу из реестра служб. Чтобы упростить тестирование сценария отмены привязки, метод register правила возвращает дескриптор регистрации службы:
|
01
02
03
04
05
06
07
08
09
10
|
@Testpublic void executeAfterListenerRemoval() { Registration registration = serviceRegistration.register( ServiceListener.class, listener ); registration.unregister(); service.execute(); verify( listener, never() ).executed();} |
Строка пять ( registration.unregister() ) удаляет шпиона слушателя из реестра службы. Это вызывает отмену привязки, и слушатель никогда не вызывается. Конечно, реальный сценарий может добавить дополнительные тесты для регистрации нескольких слушателей, обработки исключений и тому подобного, но я думаю, что концепция прояснена.
Вывод
До сих пор ServiceRegistrationRule доказала свою эффективность в нашем текущем проекте. Это значительно снижает количество шаблонов, делает тесты чище и повышает удобочитаемость. Класс является частью функции com.codeaffine.osgi.test.util репозитория Xiled P2: http://fappel.github.io/xiliary
Если вы хотите взглянуть на код или подать проблему, вы также можете взглянуть на проект Xiled GitHub: https://github.com/fappel/xiliary
Для всего остального не стесняйтесь использовать раздел комментариев ниже. Далее я объясню, как настроить сборку maven-tycho со встроенными тестами PDE, как описано выше. Это несколько сложно, так как Tycho не позволяет получить доступ к пучкам, собранным текущим реактором, так что следите за обновлениями.
| Ссылка: | Помощник по тестированию службы OSGi: ServiceRegistrationRule от нашего партнера по JCG Рудигера Херрманна в блоге Code Affine . |