java - 带有模式的 Spring MockMvc redirectedUrl

标签 java spring junit mocking

我有一个简单的 PersonController 类,它提供 save() 方法来保存来自 http post 请求的对象。

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;
    }

}

作为 save() 方法返回 return "redirect:view/"+ personId;。每个请求都会有所不同。它可能像 "view/5""view/6" 取决于已持久化的对象的 id。

然后我有一个简单的类来使用 spring mocking 测试上面的 Controller 。

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")
        );
    }


}

现在我遇到一个问题,redirectedUrl("view") 拒绝值 "view/5"。我已经尝试了 redirectedUrl("view*")redirectedUrl("view/*") 但它不起作用。


编辑:

这里我有一个解决方法,如下所示

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());

但我仍在寻找正确的方法。


更新:

我在 spring jira here 上发布了同样的问题:

最佳答案

从 spring 4.0 开始你可以使用 redirectedUrlPattern正如 Paulius Matulionis 所指出的

从 spring 3.x 开始,不支持开箱即用,但您可以轻松添加自定义结果匹配器

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());
        }
    };
}

像内置匹配器一样使用它

 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]+")
 );

关于java - 带有模式的 Spring MockMvc redirectedUrl,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17834034/

相关文章:

java - H2 中用于单元测试的现有索引

java - 在循环中累积字符串并打印出所有字符串

java - Spring-Security 从 2.0.4 迁移到 4.2.0

java - Spring Gateway RouteLocator 空指针异常

java - 覆盖 Mockito toString 测试输出

java - jUnit4.0 : how to know current test method name?

java - 在 Android/Java 上安全使用 glMapBufferRange()

java - 当 Java 中的输入缓冲区自动刷新时会发生什么?

java - Android UI 测试有时会因 Robotium 无法找到 ImageButton 对象而失败

java - 计划方法中的 NullPointer 异常