I'm trying to run 2 tests with MockMVC (Spring framework).
The first one add a user. When the user is added, an userID is generated, and returned.
The second should delete the added user from this userID.
At the start of my test class, I have this variable: String userID;
Here is the test where I create the user (it works). After creating the user, I get from the response the generated ID for this user.
#Test
public void it_adds_a_new_user() throws Exception {
MvcResult result = mockMvc
.perform(post("/users")
.contentType(MediaType.APPLICATION_JSON)
.content("User infos, in JSON..."))
.andExpect(status().isOk())
.andReturn();
//Next lines just take the ID from the response
Matcher matcher = Pattern.compile("\\d+").matcher(result.getResponse().getContentAsString());
matcher.find();
this.userID = matcher.group();
System.out.println(userID); //Correctly print the generated ID
}
Now, I try to delete this poor guy:
#Test
public void it_deletes_the_new_user() throws Exception {
System.out.println(userID); //It prints null!
mockMvc.perform(delete("/users/" + userID)
.contentType(MediaType.APPLICATION_JSON)
.andExpect(status().isOk()); //400 because userID is null :-(
}
The problem is that userID is correctly initialized in the first test, but is null in the second (it is a class variable). I don't understand why.
Can you help me running those tests, and if possible explain me why userID == null on my second test ?
Thanks!
create getter and setter method for set and get the value userID like:
void setUserId(matcher.group())---->should be inside it_adds_a_new_user()
now you have setted the userId
add one gette method also,
get the value by calling getUserId()----->should be inside it_deletes_the_new_user()
since i dont know the structuer of your program so giving you just an idea to solve you problem.
Related
Here is my test
#Test
#WithMockUser(authorities = "ADMIN")
void shouldCreateRestaurant_whenPost() throws Exception {
// when
mockMvc.perform(
post("/restaurant/admin/")
.contentType(MediaType.APPLICATION_JSON)
.content(this.objectMapper.writeValueAsString(RESTAURANT_CREATION_DOMINOS)));
// then
Mockito.verify(restaurantService, times(1)).create(RESTAURANT_CREATION_DOMINOS);
}
It fails because it compares object with =. First object RestaurantCreationDTO#5980fa73, second RestaurantCreationDTO#15a8cebd.
But how can I make sure that restaurantService is called with a valid argument?
You have two options:
First - If it is enough to check if the object in the service call is indeed a RestaurantCreationDTO:
Mockito.verify(restaurantService, times(1)).create(any(RestaurantCreationDTO.class));
Second - If you really want to check the object content in the service call
In your Test class
#Captor
ArgumentCaptor<RestaurantCreationDTO> restaurantCreationDtoCaptor;
In your Test method
Mockito.verify(restaurantService, times(1)).create(restaurantCreationDtoCaptor.capture());
assertThat(restaurantCreationDtoCaptor.getValue()).isEqual(RESTAURANT_CREATION_DOMINOS)
I'm trying to write a JUnit test for my Spring module, after seeing that my logic is working using SwaggerUI.
What happens, however, is that I miss some data in my H2 instance (used for the tests only), and I don't understand why.
This is what I'm doing:
MyObjectController.java
#PostMapping("/myobject")
public void save(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Save and get id
Integer id = service.save();
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(id).toUri();
// Run async
service.run(id); // At this stage, id = 1 because the insert completed correctly
// Return id
response.setHeader(HttpHeaders.LOCATION, location.toString());
}
MyObjectService.java
#Async
#Transactional
public void run(Integer id) throws Exception { // As above, id = 1 but this time data is not there!
// Retrieve and run
Optional<MyObject> myObject = myObjectDao.findById(id);
if (!myObject.isPresent()) {
throw new NotFound();
}
...
}
/myobject endpoint is called using MockMVC, and once called it correctly returns the expected id.
If I place a breakpoint at the beginning of service.run(Integer id), and I call /myobject using SwaggerUI, I can see that everything is fine, but this doesn't happen when running in JUnit.
Can you guys please help me with that?
I have a controller end point that looks something like so
#POST
public JobComponentGetResponse createJobComponent(
#PathParam("jobId") Integer jobId,
#Valid JobComponentPostRequest request
) {
JobComponentRecord newJobComponent = dao.jobComponent.newRecord();
newJobComponent.setJobId(jobId);
newJobComponent.setLabel(request.label);
newJobComponent.setSqft(request.sqFt);
newJobComponent.insert();
return new JobComponentGetResponse(newJobComponent);
}
And a corresponding unit test
#Test
public void createJobComponent_createsAndReturnsTheDesiredRecord() {
JobComponentPostRequest request = new JobComponentPostRequest();
JobComponentRecord jobComponent = spy(new JobComponentRecord());
when(dao.jobComponent.newRecord()).thenReturn(jobComponent);
when(jobComponent.insert()).thenReturn(null);
JobComponentGetResponse response = jobComponentController.createJobComponent(jobId, request);
assertThat(response, samePropertyValuesAs(request));
}
I'm trying to test the response of my controller but I keep getting a null pointer exception when the controller calls newJobComponent.insert()
I've tried doing when(jobComponent.insert()).thenReturn(null); and that doesn't work either.
I suspect that your dao.jobComponent.newRecord() returns null even if you do : when(dao.jobComponent.newRecord()).thenReturn(jobComponent);
What is dao.jobComponent exactly and where does it comes from ?
EDIT : I don't have a full overview of your code but a getter for JobComponentRecord would be a good idea and you could easily determine his return value with mockito.
I have my validate method in my TestValidator as follows
#Override
public void validate(Object target, Errors errors) {
Test test = (Test) target;
String testTitle = test.getTestTitle();
//**ErrorCheck1** - This works, and I am able to pull the value in my controller
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "testTitle", "test.testTitle.projec", "My msg");
if (testTitle != null && testTitle.length() < 4) {
logger.error("Inside custom validation"+test.testTitle().length());
//**Error Check2**
//***HOW DO I RETRIEVE THE BELOW VALUE in My controller
errors.rejectValue(testTitle, "test.testTitle.lessThen4");
errors.addAllErrors(errors);
logger.error("Entered If condition of validate");
}
}
And my controller is
#RequestMapping(value = "/test", method = RequestMethod.PUT)
public ResponseEntity<BasicResponseDTO> newTest(#Valid #RequestBody Test test, BindingResult result) {
if (result.hasErrors()){
logger.error("Entered Errors");
BasicResponseDTO basicResponseDTO = new BasicResponseDTO();
basicResponseDTO.setCode(ResponseCode.BAD_REQUEST);
return new ResponseEntity<BasicResponseDTO>(basicResponseDTO, HttpStatus.BAD_REQUEST);
}
}
When my ErrorCheck1 condition is activated, my IF condition inside the controller is able to retrieve it.
However, in my ErrorCheck2, because of of the errors.rejectValue I immediately get an error on the console and am not able to gracefully handle the situation when the testTitle length is less than 4.
What is the alternative to errors.rejectValue so that I may handle the
error in my controller ?
Ok - Got it. All i had to do was change
errors.rejectValue(testTitle, "test.testTitle.lessThen4");
to
errors.reject(testTitle, "test.testTitle.lessThen4");
RejectValue is a Field error and is not global in nature.
Reject is a Global error and can be accessed from inside the errors list in the controller.
From the Documentation
void reject(String errorCode, String defaultMessage);
Register a global error for the entire target object, using the given error description.
#Override
public void validate(Object target, Errors errors) {
Test test = (Test) target;
String testTitle = test.getTestTitle();
//**ErrorCheck1** - This works, and I am able to pull the value in my controller
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "testTitle", "test.testTitle.projec", "My msg");
if (testTitle != null && testTitle.length() < 4) {
logger.error("Inside custom validation"+test.testTitle().length());
//**Error Check2**
//***HOW DO I RETRIEVE THE BELOW VALUE in My controller
errors.reject(testTitle, "test.testTitle.lessThen4");
errors.addAllErrors(errors);
logger.error("Entered If condition of validate");
}
}
Hope that helps someone.
You cannot access the value directly but there is a way to include the value into error message
${validatedValue}
If you annotate a field like this
#Size(min = 10, message =”Phone number entered [${validatedValue}] is invalid. It must have at least {min} digits”)
private String phoneNumber;
and enter 123 your error message should be
Phone number entered [123] is invalid. It must have at least 10 digits. Thus you can access the value.
See https://raymondhlee.wordpress.com/2014/07/26/including-field-value-in-validation-message-using-spring-validation-framework-for-jsr-303/
#Override
public User editDescription(User user, String description) throws UserNotFoundException {
user.setAboutMe(description);
User returnedUser = userRepository.save(user);
if (returnedUser == null) {
throw new UserNotFoundException();
}
return returnedUser;
}
I have this service implementation and the test case is:
#Test
public void shouldEditDescriptionOfTheUser() throws UserNotFoundException{
databuilderService.createAll();
User user = userService.findByEmail("abc#gmail.com");
user.setAboutMe("It's a description about the user");
userService.save(user);
String aboutMe = user.getAboutMe();
LOGGER.info(aboutMe);
Assert.assertNotNull(aboutMe);
}
is this test case covering all the branches ? Should I write another test case for checking the value of user object(null checking) which is a branch in service ?
is this test case covering all the branches ?
No it does not.
Obvious it does cover nothing, because it does not invoke the method under test at all!
BTW: I do not know your repository, but it is likely that userRepository.save(user) always return the given user, so maybe the if (returnedUser == null) is nonesence, and it is more usefull to remove that if instead of writing an test for.
Should I write another test
You should start to make your first test a usefull test. This test is not a test at all. Because it does not even invoke the method under test!
Replace the Logger with an assert first and invoke the method:
#Test
public void shouldEditDescriptionOfTheUser() throws UserNotFoundException{
databuilderService.createAll(); //I would create just a single user instead
User user = userService.findByEmail("abc#gmail.com");
String newDesciption = "It's a description about the user";
Assert.notEquals("precondition", newDesciption , user.getAboutMe);
xxx.editDescription(user, newDesciption);
Assert.assertEquals(newDesciption, user.getAboutMe());
}
Maybe also check that the user is really saved.
You can also have an other test, that test that the user is created in the datebase when it was not loaded/or saved before.