I am running a unit test on a rest controller method addUser() which executes successfully without JSON path. Anytime I try to use jsonPath to perform strict data assertion to verify the content of the JSON document, I get the error No value at JSON path "$.first_name". Any help on how to fix the issue will be much appreciated. Below is the code sample
@Entity
@Table(name = "users")
public class User extends IdBaseEntity{
@JsonProperty("first_name")
@Column(name = "first_name", nullable = false, length = 45)
@NotBlank(message = "First name cannot be blank")
@Length(min = 2, max = 45)
private String firstName;
@JsonProperty("last_name")
@NotBlank(message = "Last name cannot be blank")
@Length(min = 2, max = 45)
@Column(name="last_name", nullable = false, length = 45)
private String lastName;
@NotBlank(message = "Email cannot be blank")
@Length(min = 2, max = 45)
@Column(nullable = false, unique = true, length = 45)
private String email;
@NotBlank(message = "Password name cannot be blank")
@Length(min = 2, max = 45)
@Column(nullable = false, length = 45)
private String password;
@JsonProperty("phone_number")
@Column(length = 13)
private String phoneNumber;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(
name = "users_roles",
joinColumns = @JoinColumn(name ="user_id"),
inverseJoinColumns = @JoinColumn(name="role_id")
)
private Set<Role> roles = new HashSet<>();
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
@Override
public String toString() {
return "User [firstName=" + firstName + ", lastName=" + lastName + ", email=" + email + ", password=" + password
+ ", phoneNumber=" + phoneNumber + "]";
}
}
service interface
public interface UserService {
public User addUser(User user);
}
service class
@Service
public class UserServiceImpl implements UserService{
private UserRepository userRepo;
@Autowired
public UserServiceImpl(UserRepository userRepo) {
this.userRepo = userRepo;
}
@Override
public User addUser(User user) {
return userRepo.save(user);
}
}
restcontroller class
@RestController
@RequestMapping("/api/v1/users")
public class UserRestApiController {
private UserServiceImpl userService;
public UserRestApiController(UserServiceImpl userService) {
this.userService = userService;
}
@PostMapping
public ResponseEntity<User> addUser(@RequestBody @Valid User user){
User newUser = userService.addUser(user);
URI uri = URI.create("/api/v1/users");
return ResponseEntity.created(uri).body(newUser);
}
}
test class
@WebMvcTest(UserRestApiController.class)
public class UserRestApiControllerTest {
//end point uri
private static final String END_POINT_PATH = "/api/v1/users";
@MockBean
private UserServiceImpl userService;
@Autowired MockMvc mockMvc;
@Autowired ObjectMapper objectMapper;
@Test
public void testAddUserShouldReturn201Created() throws Exception {
User user = new User();
user.setFirstName("James");
user.setLastName("Kwarteng");
user.setEmail("[email protected]");
user.setPassword("23464433");
user.setPhoneNumber("04233455");
//fakes the UserServiceImpl class
Mockito.when(userService.addUser(user)).thenReturn(user);
//convert user object to json object
String bodyContent = objectMapper.writeValueAsString(user);
//perform http request
mockMvc.perform(post(END_POINT_PATH).contentType("application/json").content(bodyContent))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.first_name", is("James")))
.andDo(print());
}
}
error after running the test. part of the error code is omitted
java.lang.AssertionError: No value at JSON path "$.first_name"
at org.springframework.test.util.JsonPathExpectationsHelper.evaluateJsonPath(JsonPathExpectationsHelper.java:302)
at org.springframework.test.util.JsonPathExpectationsHelper.assertExistsAndReturn(JsonPathExpectationsHelper.java:326)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.lang.IllegalArgumentException: json can not be null or empty
at com.jayway.jsonpath.internal.Utils.notEmpty(Utils.java:401)
json can not be null or empty. It doesn't work with jsonPath because the response body is always empty but the status is 201.The
Mockito.when...thenReturnis not propagated in the controller class.You need to involve Mockito by adding
@ExtendWith(MockitoExtension.class)instead of@WebMvcTest(UserRestApiController.class). The second step is to build aMockMvcinstance by registering theUserRestApiController@Controller instance.Below is the fixed code that works.
the MockHttpServletResponse: