I have to test this;
/** Displays the balance us page. */
#RequestMapping(value = "/profile/balance")
public ModelAndView balance(Principal principal) {
ModelAndView model = new ModelAndView("balance");
String username = principal.getName();
User user = userService.findUserByUsername(username);
model.addObject("moneyEarned", user.getMoneyEarned());
model.addObject("moneySpent", user.getMoneySpent());
return model;
}
my test looks like that;
#Test
public void getProfileBalance() throws Exception {
this.mockMvc.perform(get("/profile/balance")
.andExpect(status().isOk())
.andExpect(view().name("balance"));
}
I really don't understand how I could pass in that Principal instance.
How can I do that?
Easiest way is by doing
#Test
public void getProfileBalance() throws Exception {
SecurityContext ctx = new SecurityContextImpl();
ctx.setAuthentication(new UsernamePasswordAuthenticationToken("principal", "password"));
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_GLOBAL);
SecurityContextHolder.setContext(ctx);
this.mockMvc.perform(get("/profile/balance")
.andExpect(status().isOk())
.andExpect(view().name("balance"));
SecurityContextHolder.clearContext();
}
Or you can use the Spring Security Test library
Related
i want to test my register controller and i'm getting and error bcz posted data doesn,t tranform to my model and test fall on validation.
#PostMapping(value = "/register", consumes = "application/json")
#ResponseStatus(HttpStatus.CREATED)
private String postRegistration( #ModelAttribute #Valid final UserCreateFormDto user, final BindingResult result,
final RedirectAttributes redirectAttributes, final WebRequest webRequest) {
if (result.hasErrors()) {
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.user", result);
redirectAttributes.addFlashAttribute("user", user);
return "redirect:/register";
}
if (userService.checkEmailExist(user.getEmail())) {
return "redirect:/register?exist";
}
final User registered = userService.createNewUserAccount(user);
try {
final String appUrl = webRequest.getContextPath();
eventPublisher.publishEvent(new RegistrationCompleteEvent(registered, webRequest.getLocale(), appUrl));
return "redirect:/login?success";
} catch (UserNotExistsException e) {
return "redirect:/register";
}
}
and test
#Test
public void shouldReturnHttp201WhenUserIsCreated() throws Exception {
//given
final UserCreateFormDto userCreateFormDto = createUserCreateForm();
final User user = createUser();
given(userService.checkEmailExist(userCreateFormDto.getEmail())).willReturn(false);
given(userService.createNewUserAccount(any(UserCreateFormDto.class))).willReturn(user);
//when
final MockHttpServletResponse response = mockMvc
.perform(post("/register").with(csrf())
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsString(userCreateFormDto)))
.andReturn()
.getResponse();
//then
assertThat(response.getStatus()).isEqualTo(HttpStatus.CREATED.value());
assertThat(response.getContentAsString()).isEqualTo(userJacksonTester.write(user).getJson());
verify(userService).createNewUserAccount(refEq(userCreateFormDto));
}
I think this photo should explain as easy as it can
Edit
I tried to mock BindingResult but after reading more it wasn't a good idea.
I had one login controller in that I define one session variable, now I want to access that session variable in all my remaining controllers in my application?
this is my login controller code snippet
#RequestMapping(value = "/login", method = RequestMethod.POST,produces = "application/json")
public #ResponseBody Map<String, String> validateUser(#RequestBody String loginParameters,HttpServletRequest request) throws Exception {
try{
HttpSession session=request.getSession();
JSONObject json = new JSONObject(loginParameters.trim());
String un=json.getString("username");
session.setAttribute("username", un);
This is my ProfileController code snippet
#Controller
public class ProfileController {
#RequestMapping(value = "/getUserData", method = RequestMethod.GET,produces = "application/json")
public #ResponseBody Map<String, String> getUser(HttpServletRequest req) throws Exception {
try{
HttpSession session=req.getSession();
String loggedInUser=(String)session.getAttribute("username");
System.out.println("UserName is "+ loggedInUser);
Now I want to access this session variable(username) in my another profile controller. I tried like this but I got null pointer expection in ProfileController.
I found the solution to my requirement.
actually, my requirement is to access the session value from the login controller to profile controller.
So What I did is instead of accessing the session variable in profile controller, just I am calling a method in login controller that will return my required value.
#Controller
public class LoginController {
private HttpSession session=null;
#RequestMapping(value = "/login", method = RequestMethod.POST,produces = "application/json")
public #ResponseBody Map<String, String> validateUser(#RequestBody String loginParameters,HttpServletRequest request) throws Exception {
try{
session=request.getSession();
JSONObject json = new JSONObject(loginParameters.trim());
String un=json.getString("username");
session.setAttribute("username", un);
}catch(Exception e)
{
}
}
public String getUserName()
{
return session.getAttribute("username");
}
}
ProfileController
#Controller
public class ProfileController {
#Autowired
private LoginController loginControllerObj;
#RequestMapping(value = "/getUserData", method = RequestMethod.GET,produces = "application/json")
public #ResponseBody Map<String, String> getUser(HttpServletRequest req) throws Exception {
try{
String loggedInUser=loginControllerObj.getUserName();
System.out.println("UserName is "+ loggedInUser);
As per my understanding, in my question. I got null pointer exception in Profile controller this is because of if we want to access the session then we need to call the request.getSession()
the method that will return if any session is associated with the request then it will return that one if not then it creates a new session.the same concept in my profile controller also applied.
Instead of accessing the existing session in will create the new session because of both are two different requests.
For this reason, I follow the above code get rid of my requirement.
if it is about current logged in username then you just pass Principal parameter to controller method.
#RequestMapping(value="/login", method = RequestMethod.GET)
public String methodName(ModelMap model, Principal principal ) {
String name = principal.getName(); //get logged in username
model.addAttribute("username", name);
return "page";
}
I have a unit test to carry out based on the following part of code:
#RequestMapping(value = "/changePass", method = RequestMethod.POST)
public ModelAndView changePass(#ModelAttribute(TAPPLICATION) AppBean applicationBean, BindingResult result, ModelMap model, Principal principal, HttpServletRequest request) throws NSException, SQLException {
// ...
if (applicationBean != null
&& applicationBean.getChangePassDto() != null
&& StringUtils.isNotEmpty(applicationBean.getChangePassDto().getNewPassword())) {
String newPassword = applicationBean.getChangePassDto().getNewPassword();
// ...
}
// ...
The AppBean contains the following getter and setter:
private ChangePassDto changePassDto;
public ChangePassDto getChangePassDto() {
return changePassDto;
}
public void setChangePassDto(ChangePasswordDto changePassDto) {
this.changePassDto = changePassDto;
}
Basically when I execute the unit test the method applicationBean.getChangePassDto() is null but applicationBean is not null. How can I initialise the applicationBean.getChangePassDto() so that it does not return null? I have initialised the other non object parameters with the .param method as it can be seen in my unit test.
I am also using Powermock as unit test framework.
Please find below part of my unit test:
#Before
public void setup() {
request = new MockHttpServletRequest();
request.setAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
response = new MockHttpServletResponse();
session = new MockHttpSession();
request.setSession(session);
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
//Added viewResolver to prevent circular view path error
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/jsp/");
viewResolver.setSuffix(".jsp");
this.mockMvc = MockMvcBuilders.standaloneSetup(appController).setViewResolvers(viewResolver).build();
}
#Test
public void changePass_ExpectC() throws Exception {
PowerMockito.doNothing().when(passwordVal).validate(any(User.class), anyListOf(Params.class), any(Object.class),any(Errors.class));
mockMvc.perform(post("/changePass").param("userLogName", "JOHN").param("userLogged", "userLogged").param("password", "password123").param("newPassword", "newPassword123").param("confirmNewPassword", "newPassword123"))
.andExpect(view().name(Constants.DENIED))
.andExpect(status().isOk()
);
}
Any idea how I can intitialise applicationBean.getchangePassDto() so that it is not null?
Thanks in advance for help.
Simply create a new instance of ChangePassDto in your AppBean:
public class AppBean {
private ChangePassDto changePassDto = new ChangePassDto();
public ChangePassDto getChangePassDto() {
return changePassDto;
}
public void setChangePassDto(ChangePasswordDto changePassDto) {
this.changePassDto = changePassDto;
}
// ...
}
You then need to use the full path to the properties in the nested DTO like this:
mockMvc.perform(post("/changePass")
.param("changePassDto.userLogName", "JOHN")
.param("changePassDto.userLogged", "userLogged")
.param("changePassDto.password", "password123")
.param("changePassDto.newPassword", "newPassword123")
.param("changePassDto.confirmNewPassword", "newPassword123"))
.andExpect(view().name(Constants.DENIED))
.andExpect(status().isOk());
I have a really simple controller defined in this way:
#RequestMapping(value = "/api/test", method = RequestMethod.GET, produces = "application/json")
public #ResponseBody Object getObject(HttpServletRequest req, HttpServletResponse res) {
Object userId = req.getAttribute("userId");
if (userId == null){
res.setStatus(HttpStatus.BAD_REQUEST.value());
}
[....]
}
I tried to call using MockMvc in many different way but, I'm not able to provide the attribute "userId".
For instance, with this it doesn't work:
MockHttpSession mockHttpSession = new MockHttpSession();
mockHttpSession.setAttribute("userId", "TESTUSER");
mockMvc.perform(get("/api/test").session(mockHttpSession)).andExpect(status().is(200)).andReturn();
I also tried this, but without success:
MvcResult result = mockMvc.perform(get("/api/test").with(new RequestPostProcessor() {
public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
request.setParameter("userId", "testUserId");
request.setRemoteUser("TESTUSER");
return request;
}
})).andExpect(status().is(200)).andReturn();
In this case, I can set the RemoteUser but never the Attributes map on HttpServletRequest.
Any clue?
You add a request attribute by calling requestAttr ^^
mockMvc.perform(get("/api/test").requestAttr("userId", "testUserId")...
You could use
mvc.perform(post("/api/v1/...")
.with(request -> {
request.addHeader(HEADER_USERNAME_KEY, approver);
request.setAttribute("attrName", "attrValue");
return request;
})
.contentType(MediaType.APPLICATION_JSON)...
#ResponseStatus(HttpStatus.OK)
#GetMapping(Routes.VALIDATE_EMAIL_TOKEN + "/validate")
public String validateEmailToken(#RequestParam(value = "token") String token,
HttpServletRequest httpServletRequest) throws RestServiceException {
return credentionChangeService.getUserByToken(token, httpServletRequest);
}
//test method
#Mock
private HttpServletRequest httpServletRequest
#Mock
private MerchantCredentialsChangeService mockCredentionChangeService;
#Test
public void testValidateEmailToken() throws Exception {
final String token = "akfkldakkadjfiafkakflkd";
final String expectedUsername = "9841414141";
Mockito.when(mockCredentionChangeService.getUserByToken(Matchers.eq(token), Matchers.any(HttpServletRequest.class)))
.thenReturn(expectedUsername);
mockMvc.perform(get(Routes.VALIDATE_EMAIL_TOKEN + "/validate")
.param("token", token))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content().string(expectedUsername));
}
My main problem here is returning a string with a pathvariable value from one controller to another.
See here:
#RequestMapping(value = "/profile/{location}")
public ModelAndView profile(#PathVariable("location") String location) throws Exception {
return new ModelAndView("profile", "*", *);
}
#RequestMapping(value = "/records", method = "RequestMethod.POST")
public String inRecords(#Valid User user, BindingResult result) {
if(result.hasErrors()) {
return "profile/system";
}
else {
.....
return "somewhere";
}
}
My problem here is the return "profile/system" going to WEB-INF/views/profile/system.jsp. Am I doing anything wrong with #PathVariable or with the return statement itself?
Any suggestions?
Why you dont try something like this.
#RequestMapping(value = "/records", method = "RequestMethod.POST")
public void inRecords(#Valid User user, HttpServletResponse response) {
if(result.hasErrors()) {
response.sendRedirect("/YourApp/profile/system")
}
I think ModelAndView is taking the returned String and try to run ViewResolver that try to get the jso, avoid that calling or redirecting the request directly to the needed endpoint.
Or If you want to keep modelAndView use this
return new ModelAndView("redirect:/profile/system");