如何在Spring上下文初始化前Mock REST服务器?
如何用MockRestServiceServer测试构造函数中发起请求的Spring Bean
你的MyService在初始化阶段就通过RestTemplateBuilder创建RestTemplate并调用远程接口,这种场景下要避免真实请求,用MockRestServiceServer来模拟响应的核心思路是:让MyService使用的RestTemplate和MockServer绑定的是同一个实例,这样MockServer才能拦截到构造函数里发起的请求。下面是具体的实现步骤和代码示例:
步骤1:准备绑定了MockServer的RestTemplate
首先创建一个普通的RestTemplate,然后用MockRestServiceServer.createServer()把它和MockServer绑定,这样这个RestTemplate的所有请求都会被MockServer拦截。
步骤2:自定义RestTemplateBuilder返回绑定好的RestTemplate
因为你的MyService是通过builder.build()创建RestTemplate的,所以我们需要自定义一个RestTemplateBuilder,让它的build()方法直接返回我们刚才绑定了MockServer的RestTemplate,确保MyService拿到的是同一个实例。
步骤3:设置Mock响应规则
指定要拦截的请求URL、请求方法,然后返回预设的响应数据(可以是JSON字符串,或者用ObjectMapper把对象转成JSON)。
步骤4:初始化MyService并验证
最后创建MyService实例,此时构造函数发起的请求会被MockServer拦截并返回预设响应,之后验证Mock请求是否被触发,以及MyService的settings是否正确。
完整测试代码示例
import org.junit.jupiter.api.Test; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.web.client.RestTemplate; import com.fasterxml.jackson.databind.ObjectMapper; import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; import static org.springframework.test.web.client.response.MockRestResponseCreators.*; import static org.junit.jupiter.api.Assertions.*; class MyServiceTest { @Test void testMyServiceInitialization() throws Exception { // 1. 创建RestTemplate并绑定MockRestServiceServer RestTemplate restTemplate = new RestTemplate(); MockRestServiceServer mockServer = MockRestServiceServer.createServer(restTemplate); // 2. 自定义RestTemplateBuilder,确保build()返回绑定好的RestTemplate RestTemplateBuilder mockBuilder = new RestTemplateBuilder() { @Override public RestTemplate build() { return restTemplate; } // 如果你的业务代码用到了builder的其他配置(比如超时),重写对应的方法即可 // 示例: // @Override // public RestTemplateBuilder setConnectTimeout(Duration connectTimeout) { // // 这里可以实际配置restTemplate的超时,或者直接返回this忽略配置(根据测试需求) // restTemplate.getInterceptors().add(...); // return this; // } }; // 3. 准备测试数据和Mock规则 String testUrl = "http://test-url.com/settings"; MySettingsFromRemote mockSettings = new MySettingsFromRemote(); mockSettings.setSomeProperty("test-value"); // 设置你需要测试的属性 // 用ObjectMapper把对象转成JSON,避免手动写JSON出错 ObjectMapper objectMapper = new ObjectMapper(); String jsonResponse = objectMapper.writeValueAsString(mockSettings); // 设置Mock预期:匹配指定URL和GET方法,返回预设的JSON响应 mockServer.expect(requestTo(testUrl)) .andExpect(method(HttpMethod.GET)) .andRespond(withSuccess() .contentType(MediaType.APPLICATION_JSON) .body(jsonResponse)); // 4. 初始化MyService,构造函数的请求会被MockServer拦截 MyService myService = new MyService(mockBuilder, testUrl); // 5. 验证Mock请求被触发,并且settings属性正确 mockServer.verify(); // 验证预期的请求确实被发起了 assertNotNull(myService.settings); assertEquals("test-value", myService.settings.getSomeProperty()); } }
注意事项
- 如果你的业务代码中对RestTemplateBuilder做了额外配置(比如设置超时、添加拦截器),需要在自定义的RestTemplateBuilder中重写对应的方法,确保这些配置被应用到我们绑定了MockServer的RestTemplate上,或者根据测试需求模拟这些配置。
- 如果不需要启动Spring上下文,这种纯单元测试的方式速度更快;如果需要在集成测试中使用,可以通过自定义测试配置类,把我们的RestTemplateBuilder注册为bean,让Spring容器注入给MyService。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

