Search code examples
javaspring-bootget-request

Empty JSON response when testing SpringBoot API


I am currently building a SpringBoot API and I have the following problem :

When I try to test an GET request in a test class, the JSON returned is empty with the following log :

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /employee/1
       Parameters = {}
          Headers = []
             Body = null
    Session Attrs = {}
    
Handler:
             Type = com.openclassrooms.api.controller.EmployeeController
           Method = com.openclassrooms.api.controller.EmployeeController#getEmployee(Long)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /employee/1
       Parameters = {}
          Headers = []       
            Body = null
    Session Attrs = {}

Handler:
             Type = com.openclassrooms.api.controller.EmployeeController
           Method = com.openclassrooms.api.controller.EmployeeController#getEmployee(Long)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
            View name = null
            View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

I also get the following error : java.lang.AssertionError: No value at JSON path "$.firstName"

However, when I do the exact same GET request with Postman, I get the answer correctly.

enter image description here

For additionnal information, my test class :

package com.openclassrooms.api;

import static org.hamcrest.CoreMatchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

import java.io.PrintStream;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
//import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.ResultHandler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.openclassrooms.api.controller.EmployeeController;
import com.openclassrooms.api.models.Employee;
import com.openclassrooms.api.service.EmployeeService;

//@SpringBootTest
//@AutoConfigureWebMvc
@WebMvcTest(controllers = EmployeeController.class)
public class EmployeeControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private EmployeeService employeeService;

    @Test
    public void testGetEmployees() throws Exception {
        Employee response = new Employee();

        mockMvc.perform(get("/employee/1"))
                .andExpect(status().isOk())
                .andDo(print(System.out))
                .andExpect(jsonPath("$.firstName").value("Laurent"));

        // .andExpect(jsonPath("$[0].firstName", is("Laurent")));
    }
}

The controller class :

package com.openclassrooms.api.controller;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.openclassrooms.api.models.Employee;
import com.openclassrooms.api.service.EmployeeService;

@RestController
public class EmployeeController {

    @Autowired
    private EmployeeService employeeService;

    // Read - Get all employees

    // @return - An Iterable object of Employee full filled

    @GetMapping("/employees")
    public Iterable<Employee> getEmployees() {
        Iterable<Employee> list = employeeService.getEmployees();
        System.out.println(list);
        return list;
    }

    @GetMapping("/employee/{id}")
    public Optional<Employee> getEmployee(@PathVariable("id") final Long id) {
        Optional<Employee> emp = employeeService.getEmployee(id);

        if (emp.isPresent()) {
            System.out.println(emp.get().getFirstName());
            return emp;
        } else {
            System.out.println("ABSENT");
            return null;
        }
    }

    @GetMapping("/employee")
    public Optional<Employee> getEmployee() {
        Optional<Employee> emp = employeeService.getEmployee(1L);

        if (emp.isPresent()) {
            System.out.println(emp.get().getFirstName());
            return emp;
        } else {
            System.out.println("ABSENT");
            return emp;
        }
    }
}

The service class :

package com.openclassrooms.api.service;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.openclassrooms.api.models.Employee;
import com.openclassrooms.api.repository.EmployeeRepository;

@Service
public class EmployeeService {

    @Autowired
    private EmployeeRepository employeeRepository;

    public Optional<Employee> getEmployee(final Long id) {
        System.out.println("getEmployee ok");
        return employeeRepository.findById(id);
    }

    public Iterable<Employee> getEmployees() {
        System.out.println("getEmployees ok");
        return employeeRepository.findAll();
    }

    public void deleteEmployee(final Long id) {
        employeeRepository.deleteById(id);
    }

    public Employee saveEmployee(Employee employee) {
        Employee savedEmployee = employeeRepository.save(employee);
        return savedEmployee;
    }

}

And the model class :

package com.openclassrooms.api.models;

import jakarta.persistence.*;

import lombok.Data;

@Data
@Entity
@Table(name = "employees")
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    private String mail;

    private String password;

}

Solution

  • The way that your response is shown in the test case, shows that it is probably returning null (as you do inside the else statement). My approach would be to debug the test, set up breakpoints after the optional retrieval inside the controller, and check whether the optional is empty or not. My guess is, that in the test enviroment, you might be using a different datasource (like h2) instead of your regular one that is filled with data.