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.
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;
}
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.