«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;
}
}
Давайте посмотрим на это:
-
во-первых, новая абстракция среды, представленная в Здесь используется 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();
}
}
Обратите внимание, что эти маршаллеры сами по себе не являются bean-компонентами 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 и Jenkins
Если 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.