Spring Boot中如何用TestRestTemplate测试401未授权响应?
Spring Boot中TestRestTemplate测试401未授权场景的正确方式
问题原因
TestRestTemplate底层依赖的RestTemplate默认会将4xx、5xx这类状态码判定为错误请求,直接抛出HttpClientErrorException或ResourceAccessException,导致你无法直接获取响应对象来检查状态码。
解决方案
方法1:修改错误处理器,允许所有状态码
通过自定义ResponseErrorHandler,让RestTemplate不把401视为错误,这样就能正常返回响应对象。如果是使用@Autowired的TestRestTemplate,可以在测试类中重新配置它的错误处理器:
import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.client.DefaultResponseErrorHandler; import org.springframework.http.HttpStatus; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class JwtControllerIntegrationTest { @Autowired private TestRestTemplate testRestTemplate; @BeforeEach void setUp() { // 替换默认错误处理器,不将任何状态码视为错误 testRestTemplate.getRestTemplate().setErrorHandler(new DefaultResponseErrorHandler() { @Override protected boolean hasError(HttpStatus statusCode) { return false; } }); } @Test void testInvalidCredentialsReturns401() { // 构造错误的请求体(替换为你的实际请求DTO) AuthRequest wrongAuth = new AuthRequest("invalid-user", "wrong-pass"); HttpEntity<AuthRequest> request = new HttpEntity<>(wrongAuth); // 发送请求并获取响应 ResponseEntity<String> response = testRestTemplate.postForEntity("/authentications", request, String.class); // 验证状态码 assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); } }
方法2:捕获异常并验证状态码
如果你不想修改全局错误处理器,可以主动捕获TestRestTemplate抛出的HttpClientErrorException,从异常中提取状态码进行验证:
import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.HttpEntity; import org.springframework.http.HttpStatus; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.client.HttpClientErrorException; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class JwtControllerIntegrationTest { @Autowired private TestRestTemplate testRestTemplate; @Test void testInvalidCredentialsThrows401() { AuthRequest wrongAuth = new AuthRequest("invalid-user", "wrong-pass"); HttpEntity<AuthRequest> request = new HttpEntity<>(wrongAuth); try { testRestTemplate.postForObject("/authentications", request, String.class); // 如果没抛出异常,测试失败 fail("Expected HttpClientErrorException for invalid credentials"); } catch (HttpClientErrorException e) { // 验证异常中的状态码 assertEquals(HttpStatus.UNAUTHORIZED, e.getStatusCode()); } } }
方法3:使用exchange方法自定义请求配置
使用exchange方法时,可以更灵活地配置请求,包括指定临时的错误处理器,避免影响全局配置:
import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.http.client.DefaultResponseErrorHandler; import org.springframework.http.HttpStatus; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class JwtControllerIntegrationTest { @Autowired private TestRestTemplate testRestTemplate; @Test void testInvalidCredentialsWithExchange() { AuthRequest wrongAuth = new AuthRequest("invalid-user", "wrong-pass"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); HttpEntity<AuthRequest> request = new HttpEntity<>(wrongAuth, headers); // 创建临时的RestTemplate实例,自定义错误处理器 RestTemplate customRestTemplate = new RestTemplate(); customRestTemplate.setErrorHandler(new DefaultResponseErrorHandler() { @Override protected boolean hasError(HttpStatus statusCode) { return false; } }); TestRestTemplate customTestRestTemplate = new TestRestTemplate(customRestTemplate); ResponseEntity<String> response = customTestRestTemplate.exchange( "/authentications", HttpMethod.POST, request, String.class ); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); } }
注意事项
- 若使用Spring Boot 3.x,上述代码逻辑依然适用,仅部分包路径可能略有调整。
- 方法1会修改当前TestRestTemplate的全局错误处理行为,如果其他测试用例需要默认的错误抛出逻辑,可在
@AfterEach中恢复默认处理器。
内容的提问来源于stack exchange,提问作者Gustavo Ulises Arias Méndez
相关产品推荐
相关产品推荐

