首次编写API单元测试遇AssertionError: JSON路径$.id无值
单元测试报错
java.lang.AssertionError: No value at JSON path "$.id"排查 我首次尝试为API编写单元测试时,遇到错误java.lang.AssertionError: No value at JSON path "$.id",但通过OpenApi测试API功能正常。
测试代码
package com.RCTR.usersys; import com.RCTR.usersys.model.User; import com.RCTR.usersys.service.UserService; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.mockito.Mockito; 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.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest @AutoConfigureMockMvc public class UserControllerTest { @Autowired private MockMvc mockMvc; @Autowired private ObjectMapper objectMapper; @MockBean private UserService userService; @Test public void createUserSuccess() throws Exception { User newuser = User.builder() .id(4L) .firstName("Ion") .lastName("Popescu") .emailId("ion_popescu@gmail.com") .build(); Mockito.when(userService.saveUser(newuser)).thenReturn(newuser); String userJson = objectMapper.writeValueAsString(newuser); MockHttpServletRequestBuilder mockRequest = MockMvcRequestBuilders.post("/api/v1/user") .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content(userJson); mockMvc.perform(mockRequest) .andDo(MockMvcResultHandlers.print()) .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(4L)) .andExpect(jsonPath("$.firstName").value("Ion")) .andExpect(jsonPath("$.lastName").value("Popescu")) .andExpect(jsonPath("$.emailId").value("ion_popescu@gmail.com")); } }
控制器代码
package com.RCTR.usersys.controller; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.RCTR.usersys.model.User; import com.RCTR.usersys.service.UserService; @RestController @RequestMapping("/api/v1/") public class UserController { private final UserService userService; public UserController(UserService userService) { this.userService = userService; } @PostMapping("/user") public User saveUser(@RequestBody User user){ return userService.saveUser(user); } @GetMapping("/users") public List<User> getAllUsers(){ return userService.getAllUsers(); } @GetMapping("/users/{id}") public ResponseEntity<User> getUserById(@PathVariable("id")Long id){ User user = null; user = userService.getUserById(id); return ResponseEntity.ok(user); } @DeleteMapping("/users/{id}") public ResponseEntity<Map<String , Boolean>> deleteUser(@PathVariable("id")Long id){ boolean deleted = false; deleted = userService.deleteUser(id); Map<String,Boolean> response = new HashMap<>(); if (deleted) { response.put("deleted", true); return ResponseEntity.ok(response); } else { response.put("deleted", false); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response); } } @PutMapping("/users/{id}") public ResponseEntity<User> updateUser(@PathVariable("id")Long id,@RequestBody User user){ user = userService.updateUser(id,user); return ResponseEntity.ok(user); } }
问题原因
测试中Mockito.when(userService.saveUser(newuser)).thenReturn(newuser)使用对象实例匹配,但Spring MVC处理请求时会把JSON反序列化为全新的User对象,和你创建的newuser不是同一个实例,导致Mock的方法从未触发,userService.saveUser实际返回null,响应体中没有id字段,触发断言错误。
修复方案
方案1:匹配任意User对象(最简单)
将Mock触发条件改为匹配任意User实例:
Mockito.when(userService.saveUser(Mockito.any(User.class))).thenReturn(newuser);
方案2:基于equals方法匹配(需User类重写equals/hashCode)
如果User类已正确重写equals和hashCode,可以用eq匹配器:
Mockito.when(userService.saveUser(Mockito.eq(newuser))).thenReturn(newuser);
方案3:自定义字段匹配(更严谨)
需要验证传入的User字段符合预期时,用lambda表达式自定义匹配逻辑:
Mockito.when(userService.saveUser(Mockito.argThat(user -> user.getFirstName().equals("Ion") && user.getLastName().equals("Popescu") && user.getEmailId().equals("ion_popescu@gmail.com")))) .thenReturn(newuser);
内容的提问来源于stack exchange,提问作者GlavKng
相关产品推荐
相关产品推荐

