Перейти к основному содержимому

Тестирование REST с несколькими типами MIME

· 4 мин. чтения

1. Обзор

В этой статье основное внимание будет уделено тестированию службы REST с несколькими типами/представлениями мультимедиа.

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

2. Цели

Любой REST API должен предоставлять свои ресурсы как представления с использованием одного или нескольких типов мультимедиа. Клиент установит заголовок Accept , чтобы выбрать тип представления, который он запрашивает у службы.

Так как Ресурс может иметь несколько представлений, сервер должен будет реализовать механизм, отвечающий за выбор правильного представления. Это также известно как согласование содержания.

Таким образом, если клиент запрашивает application/xml , он должен получить XML-представление Ресурса. И если он запрашивает application/json , то он должен получить JSON.

3. Инфраструктура тестирования

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

public interface IMarshaller {
...
String getMime();
}

Затем нам нужен способ инициализировать правильный маршаллер на основе некоторой формы внешней конфигурации.

Для этого мы будем использовать Spring FactoryBean для инициализации маршаллера и простое свойство, чтобы определить, какой маршаллер использовать :

@Component
@Profile("test")
public class TestMarshallerFactory implements FactoryBean<IMarshaller> {

@Autowired
private Environment env;

public IMarshaller getObject() {
String testMime = env.getProperty("test.mime");
if (testMime != null) {
switch (testMime) {
case "json":
return new JacksonMarshaller();
case "xml":
return new XStreamMarshaller();
default:
throw new IllegalStateException();
}
}

return new JacksonMarshaller();
}

public Class<IMarshaller> getObjectType() {
return IMarshaller.class;
}

public boolean isSingleton() {
return true;
}
}

Давайте посмотрим на это:

  • во-первых, здесь используется новая абстракция Environment , представленная в Spring 3.1 — для получения дополнительной информации ознакомьтесь с подробной статьей об использовании свойств с Spring
  • мы извлекаем свойство test.mime из среды и используем его, чтобы определить, какой маршаллер создать — здесь некоторые переключатели Java 7 включают синтаксис String
  • затем маршаллер по умолчанию, если свойство вообще не определено, будет маршалером Джексона для поддержки JSON.
  • наконец — этот BeanFactory активен только в тестовом сценарии, так как мы используем поддержку @Profile , также представленную в Spring 3.1 .

Вот и все — механизм может переключаться между маршаллерами в зависимости от значения свойства test.mime .

4. Маршаллеры JSON и XML

Двигаясь дальше, нам понадобится фактическая реализация маршаллера — по одной для каждого поддерживаемого типа носителя.

Для JSON мы будем использовать Jackson в качестве базовой библиотеки:

public class JacksonMarshaller implements IMarshaller {
private ObjectMapper objectMapper;

public JacksonMarshaller() {
super();
objectMapper = new ObjectMapper();
}

...

@Override
public String getMime() {
return MediaType.APPLICATION_JSON.toString();
}
}

Для поддержки XML маршаллер использует XStream :

public class XStreamMarshaller implements IMarshaller {
private XStream xstream;

public XStreamMarshaller() {
super();
xstream = new XStream();
}

...

public String getMime() {
return MediaType.APPLICATION_XML.toString();
}
}

Обратите внимание, что эти маршаллеры сами по себе не являются компонентами Spring . Причина этого в том, что они будут загружены в контекст Spring с помощью TestMarshallerFactory; нет необходимости делать их компонентами напрямую.

5. Использование службы как с JSON, так и с XML

На этом этапе мы должны иметь возможность запустить полный интеграционный тест для развернутой службы. Использовать маршаллер очень просто: мы внедрим IMarshaller в тест:

@ActiveProfiles({ "test" })
public abstract class SomeRestLiveTest {

@Autowired
private IMarshaller marshaller;

// tests
...

}

Spring решит, какой маршаллер ввести, основываясь на значении свойства test.mime .

Если мы не укажем значение для этого свойства, TestMarshallerFactory просто вернется к маршаллеру по умолчанию — маршаллеру JSON.

6. Мейвен и Дженкинс

Если Maven настроен для запуска интеграционных тестов с уже развернутой службой REST, мы можем запустить ее, используя:

mvn test -Dtest.mime=xml

Или, если эта сборка использует этап интеграционного тестирования жизненного цикла Maven:

mvn integration-test -Dtest.mime=xml

Дополнительные сведения о том, как настроить сборку Maven для запуска интеграционных тестов, см. в статье Интеграционное тестирование с Maven .

С Jenkins мы должны настроить задание с помощью:

This build is parametrized

И добавлен параметр String : test.mime=xml . **

**

Обычная конфигурация Jenkins будет заключаться в том, чтобы задания выполняли один и тот же набор интеграционных тестов для развернутой службы — одно с XML, а другое с представлениями JSON.

7. Заключение

В этой статье показано, как тестировать REST API, который работает с несколькими представлениями. Большинство API-интерфейсов публикуют свои ресурсы в нескольких представлениях, поэтому тестирование всех них жизненно важно. Тот факт, что мы можем использовать одни и те же тесты для всех из них, просто крут.

Полную реализацию этого механизма — с использованием актуальных интеграционных тестов и проверкой как XML, так и JSON-представлений — можно найти в проекте GitHub .