Статьи

Эффективное выполнение интеграционных тестов HTTP / REST в Eclipse

В последнее время у меня была возможность использовать библиотеку OSGi-JAX-RS-Connector, написанную моим дорогим товарищем Хольгером Стаудхером . Соединитель позволяет легко публиковать ресурсы, регистрируя аннотированные типы @Path в качестве сервисов OSGi — что на самом деле работает довольно хорошо.

Хотя для меня естественно писать тесты классов обслуживания, основанные на простых тестах JUnit , также очень важно предоставить дополнительные интеграционные тесты. Эти тесты позволяют проверить доступность и функциональность таких сервисов во время выполнения. Чтобы обеспечить последнее, я использовал другого маленького помощника, написанного Holger — restfuse, который является расширением JUnit для автоматизированных тестов HTTP / REST.

Сценарий выглядит примерно так:

Сервис

1
2
3
4
5
6
7
8
9
@Path( '/message' )
public class SampleService {
 
  @GET
  @Produces( MediaType.TEXT_PLAIN )
  public String getMessage() {
    return 'Hello World';
  }
}

Контрольный пример JUnit

01
02
03
04
05
06
07
08
09
10
11
public class SampleServiceTest {
 
  @Test
  public void testGetMessage() {
    SampleService service = new SampleService();
 
    String message = service.getMessage();
 
    assertEquals( 'Hello World', message );
  }
}

Служба регистрации

1
2
3
4
5
6
7
8
9
<?xml version='1.0' encoding='UTF-8'?>
<scr:component
  name='SampleService'>
   <implementation class='sample.SampleService'/>
   <service>
      <provide interface='sample.SampleService'/>
   </service>
</scr:component>

Интеграционный тест restfuse

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
@RunWith( HttpJUnitRunner.class )
public class SampleServiceHttpTest {
 
  @Rule
  public Destination destination
    = new Destination( 'http://localhost:9092' );
 
  @Context
  private Response response;
 
  @HttpTest( method = Method.GET, path = '/services/message' )
  public void checkMessage() {
    String body = response.getBody( String.class );
    assertOk( response );
    assertEquals( MediaType.TEXT_PLAIN, response.getType() );
    assertEquals( 'HelloWorld', body );
  }
}

Бегущий сервис

Хотя все это было довольно просто, меня это как-то беспокоило, что для запуска интеграционных тестов локально требовалось сначала запустить сервер, прежде чем я смог выполнить интеграционный тест. Занимаясь поставленной задачей, я часто забывал запустить сервер и сталкивался с таймаутами соединения или чем-то подобным.

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

Для этого создайте и выберите набор тестов, который содержит все интеграционные тесты для запуска 1

… после этого перейдите на главную вкладку и выберите режим без головы …

… И, наконец, что не менее важно, настройте программные аргументы, используемые сервером, которые в нашем случае в основном касаются определения порта.

Выбор комплекта на вкладке «Плагины» содержит те же комплекты, что и в конфигурации запуска osgi, которая используется для запуска автономного сервера, а также комплекты JUnit-, PDE JUnit-, restfuse-bundles и их зависимости. Выбранный набор тестов может выглядеть так:

01
02
03
04
05
06
07
08
09
10
@RunWith( Suite.class )
@SuiteClasses( {
  SampleServiceHttpTest.class
} )
public class AllRestApiIntegrationTestSuite {
 
  public static String BASE_URL
    = 'http://localhost:'
    + System.getProperty( 'org.osgi.service.http.port' );
}

Единственная необычная вещь здесь — это определение константы BASE_URL. Как упоминалось выше, порт сервера тестового прогона указывается в качестве аргумента программы в конфигурации запуска. Но тесты restfuse должны предоставлять порт во время определения правила назначения. Использование описанного выше подхода позволяет изменить порт в конфигурации, не влияя на тесты. Просто используйте константу в качестве параметра в определении, как показано в следующем фрагменте 2 3 .

1
2
3
@Rule
 public Destination destination
   = new Destination( BASE_URL );

Эта простая установка сработала очень хорошо и улучшила мой рабочий процесс при проведении интеграционных тестов локально А сохранение конфигурации запуска в общем проекте позволяет вашим коллегам по команде повторно использовать ее.

Так что это на сегодня, и, как всегда, обратная связь высоко ценится. Кстати, Хольгер пообещал мне написать пост о том, как интегрировать описанные выше вещи в сборку на основе maven / tycho 4 — так что следите за обновлениями

  1. Конечно, вы также можете использовать возможность запуска всех тестов выбранного проекта, пакета или папки с исходным кодом, но для наших целей здесь достаточно использовать подход с использованием набора и запустить один тестовый пример.
  2. Вы, вероятно, предоставили бы отдельный класс для определения константы в реальном сценарии, чтобы избежать привязки тестов к набору. Я пропустил это здесь для упрощения.
  3. Обратите внимание, что BASE_URL включен с использованием статического импорта для лучшей читаемости фрагмента
  4. Хольгер сдержал свое обещание, см .: http://eclipsesource.com/blogs/2012/09/11/running-httprest-integration-tests-in-an-eclipse-tycho-build/

Справка: Эффективное проведение интеграционных тестов HTTP / REST в Eclipse от нашего партнера по JCG Фрэнка Аппеля из блога Code Affine .