Mock BindingResult in unit test case when user does not exist - java

I'm very new to Mockito and Junit. I'm working on creating test case for forgot password workflow. Below is the code for controller and test. Could anyone tell me how should I test on bindingresult?
#RequestMapping(value = "/user/public/forgotPassword", method = RequestMethod.POST)
public ModelAndView sendforgetPasswordLink(#ModelAttribute ForgetPasswordBean forgetPasswordBean,BindingResult result, HttpSession session) {
BreadCrumbBuilder.addLinktoBreadCrumb(session, new Link(Constants.FORGET_PASSWORD_TITLE, "/user/public/forgotPassword", Constants.GROUP_USER, 0));
Map<String, String> breadCrumbs = HomePageController.setupInitialBreadCrumbs(session);
breadCrumbs.put(Constants.FORGET_PASSWORD_TITLE, "/user/public/forgotPassword");
session.setAttribute(SessionAttributes.BREAD_CRUMBS,breadCrumbs);
ModelAndView mav = new ModelAndView();
mav.addObject("displayTitle", Constants.FORGET_PASSWORD_TITLE);
PublicUser user = publicUserService.findPublicUserByEmail(forgetPasswordBean.getEmail().toLowerCase());
if(user == null) {
result.reject("email", "An account does not exist for this email.");
mav.setViewName("publicuser/forgetPassword.jsp");
return mav;
}
String randomId = java.util.UUID.randomUUID().toString();
user.setTempId(randomId);
mailService.sendForgetPasswordLink(user);
publicUserService.savePublicUser(user);
String msg = "Password reset instructions have been sent to your email.";
mav.addObject("msg", msg);
mav.setViewName("message.jsp");
return mav;
}
This is test I created so far
#Test
public void TestForgetPasswordForNoUserFound() throws Exception {
final String input_email = "abc#test.com";
ForgetPasswordBean forgetPasswordBean = new ForgetPasswordBean();
forgetPasswordBean.setEmail(input_email);
PublicUser daoUser = new PublicUser();
daoUser.setEmail(input_email);
when(mockPublicUserService.findPublicUserByEmail(input_email)).thenReturn(null);
when(mockBindingResult.hasErrors()).thenReturn(true);
final ModelAndView modelAndView = controller.sendforgetPasswordLink(forgetPasswordBean, mockBindingResult, mockHttpSession);
ModelMap modelMap = modelAndView.getModelMap();
assertEquals("An account does not exist for this email.", modelMap.get(mockBindingResult));
assertEquals("publicuser/forgetPassword.jsp", modelAndView.getViewName());
assertModelAttributeValue(modelAndView, "displayTitle", Constants.FORGET_PASSWORD_TITLE);
}

What you can do is verify behavior of your BindingResult by checking that the reject method was called.
Basically instead of
assertEquals("An account does not exist for this email.", modelMap.get(mockBindingResult));
You can do the following
Mockito.verify(mockBindingResult).reject("email", "An account does not exist for this email.");
And that way you can verify that the method was called.

Related

Redirect ModelAndView with message

My application has a method to update a conference. After doing so I have a modelandview with a redirect to the main conference list. This all works fine although the message which I add as an object to the modelandview does not display.
My method in my controller:
#PostMapping("/updateConference")
public ModelAndView updateConference(
#ModelAttribute("conference") #Valid ConferenceDto conferenceDto, BindingResult result) {
if(result.hasErrors()){
return new ModelAndView("updateConference","conferenceDto", conferenceDto);
}
try {
conferenceService.updateConference(conferenceDto);
} catch (ConferenceAlreadyExistException uaeEx) {
ModelAndView mav = new ModelAndView("updateConference","conferenceDto", conferenceDto);
mav.addObject("message", uaeEx.getMessage());
return mav;
}
ModelAndView mav = new ModelAndView("redirect:/teacher/configure"); // Problem is here
mav.addObject("message", "Successfully modified conference.");
return mav;
}
In my html I have the line:
<div th:if="${message != null}" th:align="center" class="alert alert-info" th:utext="${message}">message</div>
After updating the conference it goes back to configure.html although the message does not show. In the url I can see http://localhost:8080/teacher/configure?message=Successfully+modified+conference
I have looked at this thread although it did not help.
I tried to experiment by setting ModelAndView mav = new ModelAndView("configure") and the message displays but my conference list is empty and the url is http://localhost:8080/teacher/updateconference
Any tips is highly appreciated!
EDIT
I have tried to use RedirectAttributes as crizzis pointed out & this page and have this now:
#PostMapping("/updateConference")
public String updateConference(
#ModelAttribute("conference") #Valid ConferenceDto conferenceDto, BindingResult result, RedirectAttributes attributes) {
if(result.hasErrors()){
attributes.addFlashAttribute("org.springframework.validation.BindingResult.conferenceDto", result);
attributes.addFlashAttribute("conferenceDto", conferenceDto);
return "redirect:/teacher/updateConference";
}
try {
conferenceService.updateConference(conferenceDto);
} catch (ConferenceAlreadyExistException uaeEx) {
attributes.addFlashAttribute("conferenceDto", conferenceDto);
attributes.addFlashAttribute("message", uaeEx.getMessage());
return "redirect:/teacher/updateConference";
}
attributes.addFlashAttribute("message", "Successfully modified conference.");
return "redirect:/teacher/configure";
}
My get method:
#GetMapping(path = "/updateConference/{id}")
public String showUpdateConferenceForm(#PathVariable(name = "id") Long id, Model model){
Optional<Conference> conference = conferenceService.findById(id);
if (!model.containsAttribute("ConferenceDto")) {
model.addAttribute("conference", new ConferenceDto());
}
return "updateConference";
}
This works as intended and my message is shown on my configure.html . However, when I have an error in BindingResults the application goes to an error page and I get this in the console:
Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported]
Use RedirectAttributes which has addFlashAttribute method. You can set the success or failure message like you did and access that message through the key in the redirected page as you need.
when the error occurs you are redirecting to the same method instead of this you can just render the template in case there is error. I do this way.

Calling RequestMapping "twice"

I couldn't figure out what to put to the title, but I have the following code:
#Controller
public class WorkdayAddController {
#Autowired
private WorkdayRepository workdayRepository;
#Autowired
private VehicleRepository vehicleRepository;
#RequestMapping(value = "addworkday")
public String addWorkday(Model model){
model.addAttribute("workdayaddform", new WorkdayAddForm());
model.addAttribute("vehicles", vehicleRepository.findAll());
return "addworkday";
}
#RequestMapping(value = "saveworkday", method = RequestMethod.POST)
public String save(#Valid #ModelAttribute("workdayaddform") WorkdayAddForm workdayaddform, BindingResult bindingResult) {
if (!bindingResult.hasErrors()) { // validation errors
Date workdayBegin = workdayaddform.getBeginDate();
Date workdayEnd = workdayaddform.getEndDate();
if (!UtilityClass.dateIsAfterDate(workdayBegin, workdayEnd)) {
bindingResult.rejectValue("beginDate", "err.beginDate", "Aloitusaika ei voi olla lopetusajan jälkeen.");
return "addworkday";
}
Workday workday = new Workday();
Vehicle vehicle = new Vehicle();
workdayRepository.save(workday);
}
else {
return "addworkday";
}
return "redirect:/workdaylist";
}
}
After the 'dateIsAfterDate' check, it should direct one to 'addworkday' again, which it does, but it doesn't add the 'vehicles' model. Is there a way around this? I thought it would somehow just direct it to the above #RequestMapping(value= "addworkday") but this seems to not be the case.
Update:
#RequestMapping(value = "addworkday")
public String addWorkday(Model model, RedirectAttributes redirectAttributes){
System.out.println(redirectAttributes); // {}
System.out.println(model); // output in comment
model.addAttribute("workdayaddform", new WorkdayAddForm()); //I guess I need to add the old workdayform here?
model.addAttribute("vehicles", vehicleRepository.findAll());
return "addworkday";
}
#RequestMapping(value = "saveworkday", method = RequestMethod.POST)
public String save(#Valid #ModelAttribute("workdayaddform") WorkdayAddForm workdayaddform,
BindingResult bindingResult,
final RedirectAttributes redirectAttributes) {
if (!bindingResult.hasErrors()) { // validation errors
Date workdayBegin = workdayaddform.getBeginDate();
Date workdayEnd = workdayaddform.getEndDate();
if (!UtilityClass.dateIsAfterDate(workdayBegin, workdayEnd)) {
// Add the vehicle you want to send to the other method.
redirectAttributes.addFlashAttribute("workdayaddform", workdayaddform);
redirectAttributes.addFlashAttribute("vehicle", vehicleRepository.findAll());
redirectAttributes.addFlashAttribute("binding", bindingResult);
return "redirect:/addworkday";
}
You need to use the #RedirectedAttributes annotation in order to send attributes to another method in a controller. Also, you will need to add "redirect:/" to your returned url.
#RequestMapping(value = "saveworkday", method = RequestMethod.POST)
public String save(#Valid #ModelAttribute("workdayaddform") WorkdayAddForm workdayaddform,
BindingResult bindingResult,
final RedirectAttributes redirectAttributes) {
if (!bindingResult.hasErrors()) { // validation errors
Date workdayBegin = workdayaddform.getBeginDate();
Date workdayEnd = workdayaddform.getEndDate();
if (!UtilityClass.dateIsAfterDate(workdayBegin, workdayEnd)) {
// Add the vehicle you want to send to the other method.
redirectAttributes.addFlashAttribute("vehicle", vehicle);
redirectAttributes.addFlashAttribute("binding", bindingResult);
return "redirect:/addworkday";
}
// More code.
else {
redirectAttributes.addFlashAttribute("vehicle", new Vehicle());
return "redirect:/addworkday";
}
}
I wasn't sure if you meant, after the in the else or inside the if, so I add them in both places, just to make sure.

retrieve a particular record information on particulad id

NewAccountDAOImpl
it is getting particular record id, username and password
according to that it should retrieve the records
#Transactional
#Modifying
public boolean checkLogin(int id, String username, String password){
System.out.println("In Check login"+ id);
System.out.println("In Check login"+ username);
System.out.println("In Check login"+ password);
Session session = sessionFactory.openSession();
boolean userFound = false;
//Query using Hibernate Query Language
//tring SQL_QUERY =" from NewAccount as n where n.id=? and n.username=? and password=?";
String SQL_Query=" from NewAccount where id=:id";
Query query = session.createQuery(SQL_Query);
query.setParameter("id",id).uniqueResult();
//query.setParameter(0,id);
//query.setParameter(1,username);
//query.setParameter(2,password);
List list = query.list();
if ((list != null) && (list.size() > 0)) {
userFound= true;
}
session.close();
return userFound;
}
controller class
getting information from bankbalance form like id,username, password.
i added them to checkLogin method parameters it returns boolean valeue
#RequestMapping(value = "/balanceSave", method = RequestMethod.GET)
public ModelAndView saveBk(ModelAndView model, HttpServletRequest req,
HttpServletResponse res, #ModelAttribute NewAccount newaccount) {
int id=Integer.parseInt(req.getParameter("id"));
String username=req.getParameter("username");
String password=req.getParameter("password");
boolean userExists = newaccountService.checkLogin( id, username, password);
if(userExists ){
model.addObject("newaccount", newaccount);
return new ModelAndView("redirect:viewBalanceMoney");
}
return new ModelAndView("BalanceForm");
}
here i am sending list data to a jsp page viewbalanc
// view newaccount balance money
#RequestMapping(value = "/viewBalanceMoney", method = RequestMethod.GET)
public ModelAndView viewBalanceMoney(ModelAndView model) {
// public NewAccount getNewAccount(int newaccountid);
List<NewAccount> listnewaccount = newaccountService.getAllNewAccounts();
model.addObject("listnewaccount", listnewaccount);
model.setViewName("viewBalanc");
return model;
}
image1 shows balance form
it send input to the controller method
image 2 shows retrieved records, but i need particular id record information
image2
enter image description here
You can do this using #PathVariable and invoke the method for that accountId.
#RequestMapping(value = "/viewBalanceMoney/{newAccountId}", method = RequestMethod.GET)
public ModelAndView viewBalanceMoney(#PathVariable("newAccountId") Integer newaccountid,
ModelAndView model) {
//write code for fetching data for newaccountid
}

Issues testing my Spring MVC Controllers

I have the following controller method. A user submits a search form with 4 input fields and has to fill in at least one of the field. If all the fields are empty (using the validator) then an error will be displayed on top of the form (in the same page).
Otherwise it will use the service method to look for users and display the results at the bottom of the form (in the same page). That is why in the if statement I return the same page as well as the end of the method because whatever happens the user is directed to the same page
#RequestMapping(value="/search", method={RequestMethod.POST})
public ModelAndView searchUser(#ModelAttribute("searchUserDTO")SearchUserDTO searchUserDTO, BindingResult bindingResult, ModelMap modelMap){
validate(searchUserDTO, bindingResult);
List<BlueUser> users = new ArrayList<>();
if (bindingResult.hasErrors()) {
modelMap.put("searchUserDTO", searchUserDTO);
return new ModelAndView(VIEW_USERS, modelMap);
} else {
users = BlueUserService.findUsers(searchUserDTO.getMyName, searchUserDTO.getSSID(), searchUserDTO.getPostcode(), new Email(searchUserDTO.getMail()));
}
modelMap.put("searchUserDTO", users);
return new ModelAndView(VIEW_USERS, modelMap);
}
validator method
#Override
public void validate(Object target, Errors errors) {
SearchUserDTO dto = (SearchUserDTO)target;
if(dto.getMyName()==null && dto.getSSID() == null && dto.getPostcode() == null && dto.getMail()==null){
errors.reject(EMPTY, "Please fill in the form");
}
}
I use reject to return error in the global scope and not on specific field and the following test method:
public static final String BINDING_RESULT = BindingResult.class.getName() + '.' + "searchUserDTO";
#Test
public void searchUserPOST() throws Exception{
MultiValueMap<String, String> paramMap = mockMVCTestUtil.createParamMap("myName", null,
"ssid", null,
"postcode", null,
"mail", null);
MvcResult mvcResult = this.mockMvc.perform(
post("/search")
.params(paramMap))
.andExpect(model().attributeExists("searchUserDTO"))
.andExpect(model().attributeHasErrors("searchUserDTO"))
.andExpect(status().isOk())
.andExpect(redirectedUrl(VIEW_USERS))
.andExpect(forwardedUrl(VIEW_USERS))
.andReturn();
BindingResult bindingResult = (BindingResult) mvcResult.getModelAndView().getModel().get(BINDING_RESULT);
assertNotNull(bindingResult);
assertGlobalErrorMessage(bindingResult, "Please fill in the form");
}
When I run the test method it fails and i get the following error messages:
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: No errors for attribute 'searchUserDTO'
What am I doing wrong?

is there any java/spring way to store session information for the current logged user using the HttpServletRequest?

I am wondering if I can set attributes on the HttpServletRequest object.
What I want to do is to store some information for the current logged user that I can later get back (on the same session).
I am using spring mvc.
So far I tried this
#RequestMapping(value = "/url1", method = RequestMethod.GET)
public void test1(final HttpServletRequest req, final ModelMap model) {
List<String> myList = (List<String>)req.getAttribute("myList");
}
#RequestMapping(value = "/url2", method = RequestMethod.GET)
public void test2(final HttpServletRequest req, final ModelMap model) {
String message = "hello world";
List<String> messages = new ArrayList<String>();
messages.add(messages);
req.setAttribute("myList", messages);
}
So far, when I make the req.getAttribute I get a null... Any idea?
To setAttribute in session should be used like this:
request.getSession().setAttribute("myList", messages);
And you can get it like this :
request.getSession().getAttribute("myList");

Categories