测试抛出NullPointerException:Response为null无法调用getBody()求助
问题解决:RestTemplate Mock 导致的 NullPointerException
问题背景
编写了获取Token的Spring方法,通过RestTemplate.exchange请求接口并返回ResponseEntity的body,但测试时抛出:
java.lang.NullPointerException: Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because "response" is null
核心错误原因
你的测试代码存在几个关键问题导致Mock未生效,restTemplate.exchange返回null:
- 测试上下文冗余:使用
@SpringBootTest启动完整Spring上下文,但这是单元测试,不需要加载整个应用,反而可能导致Mock注入异常。 - Mock参数不匹配:原方法中
exchange的第四个参数是ParameterizedTypeReference<EntityModel<TokenResponse>>,但测试里用的是eq(OauthTokenResponse.class),类型完全不匹配,Mockito无法匹配到这个调用,返回默认null。 - 返回值类型错误:测试中返回的
ResponseEntity直接封装OauthTokenResponse,但原方法期望的是EntityModel<TokenResponse>类型的响应体。 - 方法名调用错误:测试里调用的
getoToken()是笔误,原方法是getToken()。
修正后的测试代码
import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.util.ReflectionTestUtils; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.doReturn; import static org.junit.Assert.*; import org.springframework.hateoas.EntityModel; import org.springframework.http.ParameterizedTypeReference; @RunWith(MockitoJUnitRunner.class) public class OauthTokenRetrieverTest { @InjectMocks private OauthTokenRetriever oauthTokenRetriever; @Mock private RestTemplate restTemplate; @Before public void setUp() { ReflectionTestUtils.setField(oauthTokenRetriever, "oauthUrl", "https://nowhere/oauthaccess/token"); ReflectionTestUtils.setField(oauthTokenRetriever, "oauthGrantType", "client_credentials"); ReflectionTestUtils.setField(oauthTokenRetriever, "oauthUsername", "TestUser"); ReflectionTestUtils.setField(oauthTokenRetriever, "oauthPassword", "testpass"); } @Test public void testGetToken() throws JsonProcessingException { // 构造正确的返回值:EntityModel包装TokenResponse OauthTokenResponse tokenResponse = buildOauthTokenResponse(); EntityModel<OauthTokenResponse> entityModel = EntityModel.of(tokenResponse); ResponseEntity<EntityModel<OauthTokenResponse>> mockResponse = new ResponseEntity<>(entityModel, HttpStatus.OK); // 匹配ParameterizedTypeReference类型 doReturn(mockResponse) .when(restTemplate) .exchange( contains("/oauthaccess/token"), eq(HttpMethod.POST), any(HttpEntity.class), any(ParameterizedTypeReference.class)); // 调用正确的方法名 EntityModel<OauthTokenResponse> result = oauthTokenRetriever.getToken(); // 断言结果 assertEquals("ABC123", result.getContent().getAccessToken()); assertEquals("BEARER", result.getContent().getTokenType()); assertEquals("3600", result.getContent().getExpiresIn()); } private OauthTokenResponse buildOauthTokenResponse() { OauthTokenResponse oauthTokenResponse = new OauthTokenResponse(); oauthTokenResponse.setAccessToken("ABC123"); oauthTokenResponse.setTokenType("BEARER"); oauthTokenResponse.setExpiresIn("3600"); return oauthTokenResponse; } }
关键修正点说明
- 更换测试运行器:用
@RunWith(MockitoJUnitRunner.class)替代@SpringBootTest,专注于单元测试,避免不必要的上下文加载,提升测试效率。 - 匹配正确的参数类型:第四个参数用
any(ParameterizedTypeReference.class),确保Mockito能匹配到原方法的调用;如果需要更精确匹配,可以自定义ArgumentMatcher。 - 构造正确的响应体:用
EntityModel.of()包装TokenResponse,和原方法的返回类型完全一致。 - 修正方法名:将
getoToken()改为getToken(),确保调用正确的目标方法。
内容的提问来源于stack exchange,提问作者runnerpaul
相关产品推荐
相关产品推荐

