Search code examples
javatestingmockitojsonpathmockmvc

MockMVC JsonPath response has empty body?


Testing the controller gives following error: java.lang.AssertionError: No value at JSON path "$.firstName". Apparently the body of my response is empty for some reason. Controller is a RestController and and i'm correctly mocking the service. Can someone help me ?

Testclass:

@WebMvcTest(EmployeeController.class)
class EmployeeControllerTest {
    Employee employee = new Employee();

    @Autowired
    private MockMvc mvc;

    @MockBean
    private EmployeeServiceImpl service;


    @BeforeEach
    public void initEmployee() {
        employee.setFirstName("John");
        employee.setLastName("Doe");
        employee.setPlace("xxxx");
        employee.setEmployeeTitle(EmployeeTitle.SENIOR_JAVA_DEVELOPER);
        employee.setEmployeeId(1L);

    }

    @Test
    public void createEmployeeAPI() throws Exception {

        when(service.addNewEmployee(employee)).thenReturn(employee);

        mvc.perform(MockMvcRequestBuilders
                .post("/employees")
                .content(asJsonString(employee))
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON))
                .andDo(MockMvcResultHandlers.print())
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("John"));

    }

Request is correct but apparently the body is of the response is empty (see console output below):

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /employees
       Parameters = {}
          Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"124"]
             Body = {"employeeId":1,"firstName":"John","lastName":"Doe","employeeTitle":"SENIOR_JAVA_DEVELOPER","place":"xxxx","photoURrl":null}
    Session Attrs = {}

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

Controller code:

@RestController
@RequestMapping("/employees")
public class EmployeeController extends ExceptionHandling {
    private final EmployeeService employeeService;

    @Autowired
    public EmployeeController(EmployeeService employeeService) {
        this.employeeService = employeeService;
    }

    @PostMapping()
    public Employee addEmployee(@RequestBody Employee employee) {
        return employeeService.addNewEmployee(employee);
    }

Solution

  • The problem lies here:

    when(service.addNewEmployee(employee)).thenReturn(employee);
    

    Internally Mockito uses an Object class's equals() method to compare object that has been passed to the method as an argument with object configured. If equals() is not overridden then java.lang.Object’s equals() is used which compares only the references, i.e. if both variables point to one and the same object in heap. In the current example, Employe class (probably) has no equals() method implemented. When providing expected a new object is created, references are not one and the same, so Mockito will fail the verification.

    Because the employee object is serialized from json, it is not the same object.

    You can fix this by using Mockito.any() or Mockito.any(Employee.class).