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

使用MockMvc测试调用RestTemplate的控制器时返回空,如何解决?

解决Controller单元测试响应为空的问题

问题原因

  • 你的测试类中,MyController被注入了Mock的Myservice实例,Mock对象的方法默认返回null。当Controller调用myservice.getTodo()时,得到的是null,最终返回的响应体就是空字符串。
  • 你Mock了RestTemplate,但这个Mock并没有关联到Myservice上——因为你用的是Mock的Myservice,它的getTodo()方法根本不会执行实际代码,所以RestTemplate的Mock配置完全没用。

方案1:仅测试Controller层(Mock Service)

这种方式专注验证Controller的逻辑,无需关心Service内部调用,直接Stub Service方法返回预期结果即可:

@ExtendWith(SpringExtension.class)
class MyControllerTestJunit5 {

    private MockMvc mockMvc;

    @Mock
    private Myservice myservice;

    @InjectMocks
    MyController myController;

    @BeforeEach
    void setUp() {
        mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
    }

    @Test
    public void testGetTodo() throws Exception {
        // 提前准备好预期的JSON字符串
        String expectedJson = "{\"userId\":5,\"id\":6,\"title\":\"myfield\",\"completed\":true}";
        
        // Stub Service的getTodo方法,返回预设的JSON
        when(myservice.getTodo()).thenReturn(expectedJson);

        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/todo"))
                .andExpect(status().isOk())
                .andExpect(content().json(expectedJson)) // 直接验证响应JSON内容
                .andReturn();
        
        String response = result.getResponse().getContentAsString();
        System.out.println("response: " + response);
    }
}

方案2:测试Controller+Service集成(Mock RestTemplate)

如果需要验证Service调用RestTemplate的逻辑,要让Controller使用真实的Myservice实例,并将Mock的RestTemplate注入到Service中,同时处理Service的ObjectMapper依赖:

第一步:修复Service的依赖注入

@Service
public class Myservice {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    // 注意抛出序列化异常,避免编译报错
    public String getTodo() throws JsonProcessingException {
        ResponseEntity<Todo> response = restTemplate.exchange(
                "https://jsonplaceholder.typicode.com/todos/1", 
                HttpMethod.GET, 
                null, 
                Todo.class);
        Todo todo = response.getBody();
        return objectMapper.writeValueAsString(todo);
    }
}

第二步:修改测试代码

@ExtendWith(SpringExtension.class)
class MyControllerTestJunit5 {

    private MockMvc mockMvc;

    @Mock
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    private Myservice myservice;
    private MyController myController;

    @BeforeEach
    void setUp() {
        // 初始化真实Service,注入Mock的RestTemplate和ObjectMapper
        myservice = new Myservice();
        // 如果是私有字段,可用ReflectionTestUtils.setField(myservice, "restTemplate", restTemplate);
        myservice.restTemplate = restTemplate;
        myservice.objectMapper = objectMapper;
        
        // 初始化Controller,注入真实Service
        myController = new MyController();
        myController.myservice = myservice;
        
        mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
    }

    @Test
    public void testGetTodo() throws Exception {
        Todo todoSample = new Todo(5,6,"myfield", true);
        ResponseEntity<Todo> responseEntity = ResponseEntity.ok(todoSample);
        
        // Mock RestTemplate的exchange方法,精准匹配参数
        when(restTemplate.exchange(
                ArgumentMatchers.eq("https://jsonplaceholder.typicode.com/todos/1"),
                ArgumentMatchers.eq(HttpMethod.GET),
                ArgumentMatchers.isNull(),
                ArgumentMatchers.eq(Todo.class)))
                .thenReturn(responseEntity);

        String expectedJson = objectMapper.writeValueAsString(todoSample);
        
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/todo"))
                .andExpect(status().isOk())
                .andExpect(content().json(expectedJson))
                .andReturn();
        
        String response = result.getResponse().getContentAsString();
        System.out.println("response: " + response);
    }
}

内容的提问来源于stack exchange,提问作者creas443

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 06:45:38