You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试抛出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:

  1. 测试上下文冗余:使用@SpringBootTest启动完整Spring上下文,但这是单元测试,不需要加载整个应用,反而可能导致Mock注入异常。
  2. Mock参数不匹配:原方法中exchange的第四个参数是ParameterizedTypeReference<EntityModel<TokenResponse>>,但测试里用的是eq(OauthTokenResponse.class),类型完全不匹配,Mockito无法匹配到这个调用,返回默认null。
  3. 返回值类型错误:测试中返回的ResponseEntity直接封装OauthTokenResponse,但原方法期望的是EntityModel<TokenResponse>类型的响应体。
  4. 方法名调用错误:测试里调用的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:57:27