悠悠楠杉
网站页面
正文:
在Spring Boot应用中,RestTemplate作为经典的HTTP客户端工具,广泛用于服务间通信。然而,其依赖注入方式与单元测试实践常被开发者忽视,导致代码耦合度高或测试覆盖率不足。本文将系统性地解决这些问题。
新手常直接通过new RestTemplate()创建实例,但这种方式存在两大问题:
- 难以复用连接池等配置
- 无法通过Spring管理拦截器(如日志、重试机制)
通过@Bean声明配置类,统一管理参数:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplateBuilder()
.setConnectTimeout(Duration.ofSeconds(5))
.rootUri("https://api.example.com")
.build();
}
}
在服务类中通过构造函数注入:
@Service
public class UserService {
private final RestTemplate restTemplate;
public UserService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public User getUser(Long id) {
return restTemplate.getForObject("/users/{id}", User.class, id);
}
}
直接调用真实API的测试存在:
- 网络依赖导致测试不稳定
- 第三方接口频次限制
- 无法模拟异常场景
使用MockRestServiceServer模拟HTTP响应:
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@Autowired
private RestTemplate restTemplate;
private MockRestServiceServer mockServer;
@BeforeEach
void setup() {
mockServer = MockRestServiceServer.createServer(restTemplate);
}
@Test
void testGetUserSuccess() {
// 模拟响应数据
String mockResponse = "{\"id\":1,\"name\":\"John\"}";
mockServer.expect(requestTo("/users/1"))
.andRespond(withSuccess(mockResponse, MediaType.APPLICATION_JSON));
User user = userService.getUser(1L);
assertEquals("John", user.getName());
mockServer.verify();
}
@Test
void testGetUserNotFound() {
mockServer.expect(requestTo("/users/999"))
.andRespond(withStatus(HttpStatus.NOT_FOUND));
assertThrows(ResourceNotFoundException.class,
() -> userService.getUser(999L));
}
}
RestTemplate的ErrorHandler自定义异常转换逻辑ClientHttpRequestInterceptor记录请求耗时