1. 概述
本文将演示如何为Spring Boot构建的SOAP Web服务编写集成测试。相信你已经掌握应用类的单元测试编写,也熟悉Spring Boot测试的核心概念(可参考Spring Boot测试指南)。因此我们将重点聚焦于使用@WebServiceServerTest
注解专门测试Web服务层。
2. 测试Spring Web服务
在Spring Web Services框架中,接口(Endpoint)是服务端实现的核心概念。通过特殊的@Endpoint
注解标记类作为Web服务接口。这些接口的核心职责是接收XML请求消息、调用业务逻辑并返回响应消息。
2.1. Spring Web服务测试支持
测试这类接口时,我们可以简单粗暴地创建单元测试(传入参数或模拟对象)。但这种方法有个致命缺陷:无法真正验证实际传输的XML消息内容。更优方案是创建集成测试来验证消息的XML内容。
Spring Web Services 2.0引入了接口集成测试支持。**核心支持类是MockWebServiceClient
**。它提供流畅的API,向Spring应用上下文配置的接口发送XML消息,同时可设置响应预期、验证响应XML,完成完整的接口集成测试。
但这种方式会加载整个应用上下文,拖慢测试速度——在追求快速隔离测试特定接口时,这显然不是最佳选择。
2.2. Spring Boot的@WebServiceServerTest
Spring Boot 2.6通过@WebServiceServerTest
注解扩展了Web服务测试支持。我们可以用它创建仅聚焦Web服务层的测试,避免加载完整应用上下文。换句话说,它能创建只包含必需@Endpoint
Bean的测试切片,并可用@MockBean
模拟依赖项。
这与Spring Boot已有的测试切片注解(如@WebMvcTest
、@DataJpaTest
等)异曲同工。
3. 示例项目搭建
3.1. 依赖配置
鉴于我们已详细讲解过Spring Boot Web服务项目,此处仅添加测试范围所需的spring-ws-test依赖:
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-test</artifactId>
<version>4.0.10</version>
<scope>test</scope>
</dependency>
3.2. 示例Web服务
创建一个简单服务:根据产品ID返回产品数据:
@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;
}
}
这里用@Endpoint
注解标记ProductEndpoint
组件,注册为XML请求处理器。getProduct
方法接收请求对象,从仓库获取产品数据后返回响应。仓库实现细节无关紧要——我们用简单内存实现保持应用简洁,聚焦测试策略。
4. 接口测试
现在创建测试切片,验证Web服务层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://baeldung.com/spring-boot-web-service'>" +
"<bd:id>1</bd:id>" +
"</bd:getProductRequest>"
);
StringSource expectedResponse = new StringSource(
"<bd:getProductResponse xmlns:bd='http://baeldung.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"));
}
}
此测试仅配置应用中带@Endpoint
注解的Bean。该测试切片创建了一个精简的应用上下文,帮助我们构建快速精准的集成测试,避免重复加载完整上下文的性能开销。
关键点:该注解会自动配置MockWebServiceClient
及相关组件。我们可直接注入此客户端发送getProductRequest
XML请求,并通过流式断言验证结果。这些断言会验证:
- 响应XML符合指定XSD模式
- 响应XML与预期匹配
- 可用XPath表达式提取和比较响应XML中的值
4.1. 接口协作者
示例中我们用@MockBean
模拟ProductEndpoint
所需的仓库。若无此模拟,应用上下文将无法启动(因完整自动配置被禁用)。测试框架不会在执行前配置任何@Component
、@Service
或@Repository
Bean。
若需真实协作者而非模拟对象,可用@Import
声明。Spring会自动查找并注入这些类到接口中。
4.2. 加载完整上下文
如前所述,@WebServiceServerTest
不会加载完整应用上下文。若测试需要完整上下文,应组合使用@SpringBootTest
和@AutoConfigureMockWebServiceClient
。此后可按类似方式发送请求并验证响应。
5. 总结
本文探讨了Spring Boot引入的@WebServiceServerTest
注解。我们首先概述了Web服务应用的测试支持,随后演示如何使用该注解创建Web服务层测试切片,构建快速精准的集成测试。
完整源码见GitHub仓库。