8

今天开始在办公室学习 Spring Test MVC 框架,它看起来很方便,但马上就面临一些严重的问题。花了几个小时谷歌搜索,但找不到与我的问题相关的任何内容。

这是我非常简单的测试类:

import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = WebAppContext.class)
public class ControllerTests {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        mockMvc = webAppContextSetup(wac).build();
    }

    @Test
    public void processFetchErrands() throws Exception {
        mockMvc.perform(post("/errands.do?fetchErrands=true"))
               .andExpect(status().isOk())
               .andExpect(model().attribute("errandsModel", allOf(
                   hasProperty("errandsFetched", is(true)),
                   hasProperty("showReminder", is(false)))));
    }
}

测试到达以下控制器,但if由于未正确授权,第一个子句失败。

@RequestMapping(method = RequestMethod.POST, params="fetchErrands")
public String processHaeAsioinnit(HttpSession session, HttpServletRequest request, ModelMap modelMap,
                                  @ModelAttribute(ATTR_NAME_MODEL) @Valid ErrandsModel model,
                                  BindingResult result, JopoContext ctx) {
  if (request.isUserInRole(Authority.ERRANDS.getCode())) {
    return Page.NO_AUTHORITY.getCode();
  }

  [...]
}

如何为MockHttpServletRequest创建者添加用户角色MockMvcRequestBuilders.post(),以便通过对控制器的权限检查?

我知道MockHttpServletRequest有一个 method addUserRole(String role),但由于MockMvcRequestBuilders.post()返回 a MockHttpServletRequestBuilder,我从来没有得到我的手MockHttpServletRequest,因此无法调用该方法。

检查 Spring 源代码,MockHttpServletRequestBuilder没有与用户角色相关的方法,也没有MockHttpServletRequest.addUserRole(String role)在该类中调用过,所以我不知道如何告诉它在请求中添加用户角色。

我能想到的只是在过滤器链中添加一个自定义过滤器并HttpServletRequestWrapper从那里调用一个自定义来提供 的实现isUserInRole(),但是对于这种情况来说这似乎有点极端。当然,该框架应该提供更实用的东西?

4

5 回答 5

9

我想我找到了更简单的方法

@Test
@WithMockUser(username = "username", roles={"ADMIN"})
public void testGetMarkupAgent() throws Exception {

    mockMvc.perform(get("/myurl"))
            .andExpect([...]);
}

您可能需要以下 Maven 条目

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <version>4.0.4.RELEASE</version>
        <scope>test</scope>
    </dependency>
于 2017-01-05T00:43:22.997 回答
2

Spring MVC Test 有 principal() 方法,允许模拟这种情况下的请求凭证。这是设置了一些模拟凭据的测试示例:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("classpath:spring/mvc-dispatcher-servlet.xml")
public class MobileGatewayControllerTest {

private MockMvc mockMvc;

@Autowired
private WebApplicationContext wac;  

@Autowired
private Principal principal;

@Autowired
private MockServletContext servletContext;

@Before 
public void init()  {
    mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}


@Test
public void testExampleRequest() throws Exception {

    servletContext.declareRoles("ROLE_1");

    mockMvc.perform(get("/testjunit")
    .accept(MediaType.APPLICATION_JSON)
    .principal(principal))
    .andDo(print())
    .andExpect(status().isOk())
    .andExpect(content().contentType("application/json"))
    .andExpect(jsonPath("$.[1]").value("test"));
}

}

这是如何创建模拟主体的示例:

@Configuration
public class SetupTestConfig {

@Bean
public Principal createMockPrincipal()  {
    Principal principal = Mockito.mock(Principal.class);
    Mockito.when(principal.getName()).thenReturn("admin");  
    return principal;
}

}

于 2014-01-02T15:19:08.953 回答
1

还有一种简单的替代方法可以为单个请求设置特定的用户角色。如果您只想以授权用户身份执行单个操作(例如设置测试夹具),然后检查具有不同角色的用户是否可以执行某些操作,这可能会很方便:

ResultActions registerNewUserAsAdmin(String username, String password) throws Exception {
    final SignUpRequest signUpPayload = new SignUpRequest(username, password);

    final MockHttpServletRequestBuilder registerUserRequest = post(SIGN_UP_URL)
        .with(user("admin").roles("ADMIN"))
        .contentType(MediaType.APPLICATION_JSON_UTF8)
        .content(jsonMapper.writeValueAsString(signUpPayload));

    return mockMvc.perform(registerUserRequest);
}

有关更多详细信息,请参阅SecurityMockMvcRequestPostProcessors

于 2018-09-07T12:11:20.430 回答
1

您可以注入一个RequestPostProcessor来配置MockHttpServletRequest在请求中使用它之前。

MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/")
                    .with(new RoleRequestPostProcessor("some role"));

class RoleRequestPostProcessor implements RequestPostProcessor {
    private final String role;

    public RoleRequestPostProcessor(final String role) {
        this.role = role;
    }

    @Override
    public MockHttpServletRequest postProcessRequest(final MockHttpServletRequest request) {
        request.addUserRole(role);
        return request;
    }
}
于 2016-11-17T18:18:36.873 回答
0

如果您使用的是权限而不是角色,请在请求中授予权限,如下所示。

mockMvc.perform(
            put(REQUEST_URL).param(PARM, VALUE)
                    .with(SecurityMockMvcRequestPostProcessors.user(USERNAME).authorities(new SimpleGrantedAuthority("ADMIN")))                        
                    .contentType(APPLICATION_FORM_URLENCODED)
    )
于 2021-03-02T00:01:01.963 回答