mockito 使用mockMvc模拟restTemplate时出现问题

f45qwnt8  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(296)

我需要为调用服务的rest控制器端点编写单元测试,该服务调用RestTemplate exchange()

@RestController
public class MyController {

    @Autowired
    Myservice myservice;

    @GetMapping("todo")
    public ResponseEntity<String> getTodo() {
        String todoJson = myservice.getTodo();
        return ResponseEntity.ok(todoJson);
    }
}

这是我的服务类

@Service
public class Myservice {

    public String  getTodo() {
        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;

    @InjectMocks
    MyController myController;

    @Mock
    Myservice myservice;

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

    @Test
    public void mockResttemplate() throws Exception {
        Todo todosample = new Todo(5,6,"myfield", true);

        ResponseEntity<Todo> responseEntity  = ResponseEntity.ok(todosample);

        when(restTemplate.exchange(
                ArgumentMatchers.anyString(),
                any(HttpMethod.class),
                ArgumentMatchers.any(),
                ArgumentMatchers.eq(Todo.class)))
                .thenReturn(responseEntity);

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

在最后打印响应显示响应是空的。2我怎样才能让它工作呢?

zsbz8rwp

zsbz8rwp1#

我假设您希望获得todosample对象的JSON表示。测试中的问题是您通过使用@Mock注解Myservice来模拟Myservice。这个模拟的服务被MyController使用,因为它是使用@InjectMocks注解的。因此,当您调用/todo端点时,控制器调用myservice.getTodo(),它返回null,因为Myservice模拟没有被配置为返回任何其他内容。在此之后,null值将被传播到ResponseEntity主体,该主体将在测试中具体化为空的OK响应。
我相信,对于这种测试,更好的方法是模拟Myservice并对其进行正确的配置。第一部分已经完成了,正如我提到的。配置很简单。您只需将restTemplate.exchange调用配置替换为myservice.getTodo()调用配置。类似于以下内容应该可以工作:

@Test
public void mockResttemplate() throws Exception {
    String todosampleJson = "{}"; // just empty json

    when(myservice.getTodo()).thenReturn(todosampleJson);

    MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/todo"))
            .andExpect(status().isOk())
            .andReturn();
    String myresult = result.getResponse().getContentAsString();
    System.out.println("response: " + myresult); // will print "{}" now
}

然后,您可以对Myservice进行单独的测试,其中您必须模拟restTemplate.exchange调用。
当然,从技术上讲,您仍然可以在MyController测试中模拟restTemplate,但您必须确保示例化真实的Myservice,而不是模拟的版本。然而,在这种情况下,您将向MyController类公开Myservice的实现细节,这与MVC模式有点矛盾。

相关问题