如何使用spring 3.2新mvc测试登录用户

2022-09-02 03:10:05

这工作正常,直到我必须测试需要登录用户的服务,如何将用户添加到上下文中:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-test.xml")
@WebAppConfiguration
public class FooTest {
@Autowired
private WebApplicationContext webApplicationContext;

private MockMvc mockMvc;

@Resource(name = "aService")
private AService aService; //uses logged in user

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

答案 1

如果你想将MockMVC与最新的spring安全测试包一起使用,请尝试以下代码:

Principal principal = new Principal() {
        @Override
        public String getName() {
            return "TEST_PRINCIPAL";
        }
    };
getMockMvc().perform(get("http://your-url.com").principal(principal))
        .andExpect(status().isOk()));

请记住,您必须使用基于主体的身份验证才能使其正常工作。


答案 2

如果成功的身份验证产生了一些cookie,那么您可以捕获该cookie(或仅捕获所有cookie),并在下一个测试中传递它:

@Autowired
private WebApplicationContext wac;

@Autowired
private FilterChainProxy filterChain;

private MockMvc mockMvc;

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

@Test
public void testSession() throws Exception {
    // Login and save the cookie
    MvcResult result = mockMvc.perform(post("/session")
      .param("username", "john").param("password", "s3cr3t")).andReturn();
    Cookie c = result.getResponse().getCookie("my-cookie");
    assertThat(c.getValue().length(), greaterThan(10));

    // No cookie; 401 Unauthorized
    mockMvc.perform(get("/personal").andExpect(status().isUnauthorized());

    // With cookie; 200 OK
    mockMvc.perform(get("/personal").cookie(c)).andExpect(status().isOk());

    // Logout, and ensure we're told to wipe the cookie
    result = mockMvc.perform(delete("/session").andReturn();
    c = result.getResponse().getCookie("my-cookie");
    assertThat(c.getValue().length(), is(0));
}

虽然我知道我没有在这里提出任何HTTP请求,但我有点喜欢上述集成测试与我的控制器和Spring Security实现的更严格的分离。

为了使代码不那么冗长,我在发出每个请求后使用以下命令合并cookie,然后在每个后续请求中传递这些cookie:

/**
 * Merges the (optional) existing array of Cookies with the response in the
 * given MockMvc ResultActions.
 * <p>
 * This only adds or deletes cookies. Officially, we should expire old
 * cookies. But we don't keep track of when they were created, and this is
 * not currently required in our tests.
 */
protected static Cookie[] updateCookies(final Cookie[] current,
  final ResultActions result) {

    final Map<String, Cookie> currentCookies = new HashMap<>();
    if (current != null) {
        for (Cookie c : current) {
            currentCookies.put(c.getName(), c);
        }
    }

    final Cookie[] newCookies = result.andReturn().getResponse().getCookies();
    for (Cookie newCookie : newCookies) {
        if (StringUtils.isBlank(newCookie.getValue())) {
            // An empty value implies we're told to delete the cookie
            currentCookies.remove(newCookie.getName());
        } else {
            // Add, or replace:
            currentCookies.put(newCookie.getName(), newCookie);
        }
    }

    return currentCookies.values().toArray(new Cookie[currentCookies.size()]);
}

...和一个小帮手,因为至少需要一个饼干:cookie(...)

/**
 * Creates an array with a dummy cookie, useful as Spring MockMvc
 * {@code cookie(...)} does not like {@code null} values or empty arrays.
 */
protected static Cookie[] initCookies() {
    return new Cookie[] { new Cookie("unittest-dummy", "dummy") };
}

...最终得到:

Cookie[] cookies = initCookies();

ResultActions actions = mockMvc.perform(get("/personal").cookie(cookies)
  .andExpect(status().isUnauthorized());
cookies = updateCookies(cookies, actions);

actions = mockMvc.perform(post("/session").cookie(cookies)
  .param("username", "john").param("password", "s3cr3t"));
cookies = updateCookies(cookies, actions);

actions = mockMvc.perform(get("/personal").cookie(cookies))
  .andExpect(status().isOk());
cookies = updateCookies(cookies, actions);

推荐