Spring Boot MockMvc测试报错:No mapping for GET /content及JSON断言失败
问题:Spring Boot控制器MockMvc测试报错:No mapping for GET /content及JSON路径断言失败
错误日志
10:24:51.840 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet -- Initializing Servlet '' 10:24:51.842 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet -- Completed initialization in 1 ms 10:24:51.865 [main] WARN org.springframework.web.servlet.PageNotFound -- No mapping for GET /content java.lang.AssertionError: No value at JSON path "$.duration"
ContentController代码
package com.example.sixth.controller; import com.example.sixth.entity.Content; import com.example.sixth.service.ContentService; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Optional; @RestController public class ContentController { private final ContentService contentService; public ContentController(ContentService contentService) { this.contentService = contentService; } @GetMapping("/content") public List<Content> show(){ return contentService.showAll(); } @PostMapping("/content") public String save(@RequestBody Content content){ return contentService.save(content); } @GetMapping("/content/title/{param}") public List<Content> getContentStartWith(@PathVariable("param") String title){ return contentService.getContentStartWith(title); } @DeleteMapping("/content/{id}") public String delete(@PathVariable Integer id){ return contentService.delete(id); } @GetMapping("/id") public List<Content>getById(@RequestParam Integer minId, @RequestParam Integer maxId){ return contentService.getById(minId,maxId); } @GetMapping("/content/{id}") public Optional<Content> findById(@PathVariable Integer id){ return contentService.findById(id); } }
测试类代码
package com.example.sixth; import com.example.sixth.controller.ContentController; import com.example.sixth.entity.Content; import com.example.sixth.service.ContentService; import com.example.sixth.service.ContentServiceImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvcBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import java.util.ArrayList; import java.util.List; import java.util.Optional; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; @AutoConfigureMockMvc //@SpringBootTest public class ContentControllerTest { @Autowired MockMvc mockMvc; @Mock ContentService mockService; @InjectMocks ContentController contentController; @BeforeEach public void init(){ MockitoAnnotations.initMocks(this); this.mockMvc= MockMvcBuilders.standaloneSetup(mockService).build(); } @Test public void testfindall() throws Exception { Content content = (Content.builder() .id(3) .title("SECOND!!") .duration(38) .location("Bangalore").build()); List<Content> contentList = new ArrayList<>(); contentList.add(content); Mockito.when(mockService.showAll()).thenReturn(contentList); mockMvc.perform(MockMvcRequestBuilders.get("/content").contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.jsonPath("$.duration",is(content.getDuration()))); // List<Content> actual=contentController.show(); // System.out.println(actual.get(0).toString()); // assertEquals(actual,contentList); } }
注:普通断言测试功能正常,但MockMvc测试触发上述错误
问题原因及修复方案
1. MockMvc初始化错误
standaloneSetup方法需要传入控制器实例,而非Service的Mock对象。原代码传入mockService导致MockMvc无法识别/content的请求映射,出现路径匹配警告。
修复代码:
@BeforeEach public void init(){ MockitoAnnotations.initMocks(this); // 改为注入控制器实例 this.mockMvc= MockMvcBuilders.standaloneSetup(contentController).build(); }
2. JSON路径断言错误
控制器show()方法返回List<Content>,对应JSON结构是数组而非单个对象。原断言$.duration是在根对象下查找字段,实际应定位数组第一个元素的属性。
修复代码:
mockMvc.perform(MockMvcRequestBuilders.get("/content").contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$[0].duration", is(content.getDuration())));
可选:简化测试配置
使用@WebMvcTest(ContentController.class)替代@AutoConfigureMockMvc,Spring会自动配置MockMvc并仅加载目标控制器组件,配合@MockBean可简化Mock注入:
@WebMvcTest(ContentController.class) public class ContentControllerTest { @Autowired MockMvc mockMvc; @MockBean ContentService mockService; @Test public void testfindall() throws Exception { Content content = Content.builder() .id(3) .title("SECOND!!") .duration(38) .location("Bangalore").build(); List<Content> contentList = new ArrayList<>(); contentList.add(content); Mockito.when(mockService.showAll()).thenReturn(contentList); mockMvc.perform(MockMvcRequestBuilders.get("/content") .contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$[0].duration", is(content.getDuration()))); } }
内容的提问来源于stack exchange,提问作者harsh agarwal
相关产品推荐
相关产品推荐

