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

Spring Интеграционные тесты веб-сервисов с @WebServiceServerTest

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

1. Введение

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

Мы уже знаем, как писать модульные тесты для классов приложений, и мы уже рассмотрели общие концепции тестирования в нашем руководстве по тестированию в Spring Boot . Итак, здесь мы сосредоточимся на интеграционном тестировании только уровня веб-сервиса, используя @WebServiceServerTest .

2. Тестирование веб-сервисов Spring

В Spring Web Services конечные точки являются ключевым понятием для реализации службы на стороне сервера. Специализированная аннотация @Endpoint помечает аннотированный класс как конечную точку веб-службы. Важно отметить, что эти конечные точки отвечают за получение сообщений запроса XML, вызов необходимой бизнес-логики и возврат результата в виде ответного сообщения .

2.1. Поддержка тестирования веб-сервисов Spring

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

В Spring Web Services 2.0 появилась поддержка интеграционного тестирования таких конечных точек. Основным классом, обеспечивающим эту поддержку, является MockWebServiceClient . Он предоставляет гибкий API для отправки XML-сообщений в соответствующую конечную точку, настроенную в контексте приложения Spring. Кроме того, мы можем настроить ожидаемый ответ, проверить XML-код ответа и выполнить полный интеграционный тест для нашей конечной точки.

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

2.2. Весенняя загрузка @WebServiceServerTest

Spring Boot 2.6 расширил поддержку тестирования веб-сервисов с помощью аннотации @WebServiceServerTest .

Мы можем использовать это для тестов, фокусирующихся только на уровне веб-сервиса, а не на загрузке всего контекста приложения . Другими словами, мы можем создать тестовый фрагмент, содержащий только необходимые bean-компоненты @Endpoint , и мы можем имитировать любые зависимости, используя @MockBean .

Это очень похоже на удобные аннотации тестовых фрагментов , уже предоставленные Spring Boot, такие как @WebMvcTest , @DataJpaTest и другие.

3. Настройка примера проекта

3.1. Зависимости

Поскольку мы уже подробно рассмотрели проект веб-службы Spring Boot , здесь мы просто включим дополнительную зависимость spring-ws-test с тестовой областью, необходимую для нашего проекта:

<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-test</artifactId>
<version>3.1.3</version>
<scope>test</scope>
</dependency>

3.2. Пример веб-службы

Далее давайте создадим простой сервис для возврата некоторых данных о продукте для указанного идентификатора продукта:

@Endpoint
public class ProductEndpoint {

@Autowired
private ProductRepository productRepository;

@ResponsePayload
public GetProductResponse getProduct(@RequestPayload GetProductRequest request) {
GetProductResponse response = new GetProductResponse();
response.setProduct(productRepository.findProduct(request.getId()));
return response;
}
}

Здесь мы аннотировали компонент ProductEndpoint с помощью @Endpoint, который регистрирует его для обработки соответствующего XML-запроса.

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

4. Тестирование конечной точки

Наконец, мы можем создать тестовый слайс и проверить правильность обработки наших XML-сообщений на уровне веб-сервиса:

@WebServiceServerTest
class ProductEndpointIntegrationTest {

@Autowired
private MockWebServiceClient client;

@MockBean
private ProductRepository productRepository;

@Test
void givenXmlRequest_whenServiceInvoked_thenValidResponse() throws IOException {
Product product = createProduct();
when(productRepository.findProduct("1")).thenReturn(product);

StringSource request = new StringSource(
"<bd:getProductRequest xmlns:bd='http://foreach.com/spring-boot-web-service'>" +
"<bd:id>1</bd:id>" +
"</bd:getProductRequest>"
);

StringSource expectedResponse = new StringSource(
"<bd:getProductResponse xmlns:bd='http://foreach.com/spring-boot-web-service'>" +
"<bd:product>" +
"<bd:id>1</bd:id>" +
"<bd:name>Product 1</bd:name>" +
"</bd:product>" +
"</bd:getProductResponse>"
);

client.sendRequest(withPayload(request))
.andExpect(noFault())
.andExpect(validPayload(new ClassPathResource("webservice/products.xsd")))
.andExpect(payload(expectedResponse))
.andExpect(xpath("/bd:getProductResponse/bd:product[1]/bd:name", NAMESPACE_MAPPING)
.evaluatesTo("Product 1"));
}
}

Здесь мы только настроили bean-компоненты, аннотированные @Endpoint в приложении для нашего интеграционного теста. Другими словами, этот тестовый слайс создает уменьшенный контекст приложения . Это помогает нам создавать целевые и быстрые интеграционные тесты без потери производительности, связанной с многократной загрузкой всего контекста приложения.

Важно отметить, что эта аннотация также настраивает MockWebServiceClient вместе с другими соответствующими автоконфигурациями . В результате мы можем подключить этот клиент к нашим тестам и использовать его для отправки XML- запроса getProductRequest , за которым следуют различные ожидания.

Ожидания проверяют, соответствует ли ответ XML заданной схеме XSD и соответствует ли он ожидаемому ответу XML. Мы также можем использовать выражения XPath для оценки и сравнения различных значений из XML-ответа.

4.1. Соавторы конечных точек

В нашем примере мы использовали @MockBean для имитации репозитория, необходимого в нашей ProductEndpoint . Без этого макета контекст приложения не может запускаться, так как полная автоматическая настройка отключена. Другими словами, среда тестирования не настраивает компоненты @Component , @Service или @Repository перед выполнением теста .

Однако, если нам нужны реальные соавторы вместо моков, мы можем объявить их с помощью @Import . Spring будет искать эти классы, а затем подключать их к конечным точкам по мере необходимости.

4.2. Загрузка всего контекста

Как упоминалось ранее, @WebServiceServerTest не будет загружать весь контекст приложения. Если нам нужно загрузить весь контекст приложения для теста, нам следует рассмотреть возможность использования @SpringBootTest в сочетании с @AutoConfigureMockWebServiceClient. Затем мы можем использовать этот клиент аналогичным образом для отправки запроса и проверки ответа, как показано ранее.

5. Вывод

В этой статье мы рассмотрели аннотацию @WebServiceServerTest, представленную в Spring Boot.

Изначально мы говорили о поддержке тестирования Spring Boot в приложении веб-сервисов. Далее мы увидели, как с помощью этой аннотации создать тестовый фрагмент для уровня веб-сервиса, который помогает создавать быстрые и целенаправленные интеграционные тесты.

Как обычно, полный исходный код доступен на GitHub .