Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MockMvc redirectedUrl with pattern

I have a simple PersonController class that provides save() method to persist the object from http post request.

package org.rw.controller;

import java.sql.Timestamp;
import java.util.List;

import org.rw.entity.Person;
import org.rw.service.PersonService;
import org.rw.spring.propertyeditor.TimestampPropertyEditor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
@RequestMapping(value="/person")
public class PersonController {

    private static final Logger logger = LoggerFactory.getLogger(PersonController.class);

    @Autowired
    private PersonService personService;

    @Autowired
    TimestampPropertyEditor timestampPropertyEditor;


    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Timestamp.class, "dob", timestampPropertyEditor);
    }


    @RequestMapping(value="/save", method=RequestMethod.POST)
    public String save(Model model, Person person) {
        Long personId = personService.save(person);
        return "redirect:view/" + personId;
    }

}

As the save() method returns as return "redirect:view/" + personId;. It will be diffrerent for every request. it may be like "view/5" or "view/6" depending on the id of the object that has been persisted.

Then i have a simple class to test the above controller with spring mocking.

package org.rw.controller;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Test;
import org.rw.service.UserService;
import org.rw.test.SpringControllerTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

public class PersonControllerTest extends SpringControllerTest {


    @Autowired
    private UserService userService;


    @Test
    public void add() throws Exception {
        mockMvc.perform(get("/person/add", new Object[0])).andExpect(status().isOk());
    }


    @Test
    public void save() throws Exception {
        UserDetails userDetails = userService.findByUsername("anil");
        Authentication authToken = new UsernamePasswordAuthenticationToken (userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authToken);

        mockMvc.perform(
            post("/person/save", new Object[0])
                .param("firstName", "JunitFN")
                .param("lastName", "JunitLN")
                .param("gender", "M")
                .param("dob", "11/02/1989")
        ).andExpect(
                redirectedUrl("view")
        );
    }


}

now here i have a problem that redirectedUrl("view") is rejecting value "view/5". I have tried redirectedUrl("view*") and redirectedUrl("view/*") but its not working.


Edit :

Here I have got a workaround as per below

MvcResult result = mockMvc.perform(
    post("/person/save", new Object[0])
        .param("firstName", "JunitFN")
        .param("lastName", "JunitLN")
        .param("gender", "MALE")
        .param("dob", "11/02/1989")
).andExpect(
        //redirectedUrl("view")
        status().isMovedTemporarily()
).andReturn();

MockHttpServletResponse response = result.getResponse();

String location = response.getHeader("Location");

Pattern pattern = Pattern.compile("\\Aview/[0-9]+\\z");
assertTrue(pattern.matcher(location).find());

but still i am looking for the proper way.


update:

I have posted the same issue on spring jira here :

like image 623
Anil Bharadia Avatar asked Jul 24 '13 12:07

Anil Bharadia


2 Answers

Since spring 4.0 you can use redirectedUrlPattern as pointed by Paulius Matulionis

As of spring 3.x this is not supported out of the box but you can easily add you custom result matcher

private static ResultMatcher redirectedUrlPattern(final String expectedUrlPattern) {
    return new ResultMatcher() {
        public void match(MvcResult result) {
            Pattern pattern = Pattern.compile("\\A" + expectedUrlPattern + "\\z");
            assertTrue(pattern.matcher(result.getResponse().getRedirectedUrl()).find());
        }
    };
}

And use it like build-in matcher

 mockMvc.perform(
    post("/person/save", new Object[0])
        .param("firstName", "JunitFN")
        .param("lastName", "JunitLN")
        .param("gender", "M")
        .param("dob", "11/02/1989")
 ).andExpect(
        redirectedUrlPattern("view/[0-9]+")
 );
like image 148
Roman Konoval Avatar answered Nov 18 '22 11:11

Roman Konoval


Since 4.0 it is available in Spring itself.

Please check here.

like image 44
Paulius Matulionis Avatar answered Nov 18 '22 12:11

Paulius Matulionis