Java 如何使用Spring3.2新mvc测试登录用户
在我必须测试需要登录用户的服务之前,这一切都很正常。如何将用户添加到上下文:Java 如何使用Spring3.2新mvc测试登录用户,java,spring,spring-mvc,junit,Java,Spring,Spring Mvc,Junit,在我必须测试需要登录用户的服务之前,这一切都很正常。如何将用户添加到上下文: @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext-test.xml") @WebAppConfiguration public class FooTest { @Autowired private WebApplicationContext webApplicationContext;
@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();
}
您应该能够将用户添加到安全上下文中:
List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
list.add(new GrantedAuthorityImpl("ROLE_USER"));
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, password,list);
SecurityContextHolder.getContext().setAuthentication(auth);
List List=new ArrayList();
添加(新的授权机构impl(“角色用户”);
UsernamePasswordAuthenticationToken auth=新的UsernamePasswordAuthenticationToken(用户、密码、列表);
SecurityContextHolder.getContext().setAuthentication(auth);
如果要在最新的spring安全测试包中使用MockMVC,请尝试以下代码:
Principal principal = new Principal() {
@Override
public String getName() {
return "TEST_PRINCIPAL";
}
};
getMockMvc().perform(get("http://your-url.com").principal(principal))
.andExpect(status().isOk()));
请记住,您必须使用基于主体的身份验证才能工作。如果成功的身份验证生成一些cookie,则您可以捕获该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安全实现之间更严格的分离
为了使代码不那么冗长,我在发出每个请求后使用以下方法合并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[] 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);
为什么校长的解决方案对我不起作用,因此,我想提出另一种解决方法:
mockMvc.perform(get("your/url/{id}", 5).with(user("anyUserName")))
对于Spring4,此解决方案使用会话而不是cookie模拟formLogin和logout,因为spring安全测试不返回cookie 因为继承测试不是最佳做法,所以可以在测试中@Autowire该组件并调用其方法 使用此解决方案,如果您在测试结束时调用了
performLogin
,则在mockMvc
上执行的每个操作都将被称为已验证
import org.springframework.beans.factory.annotation.Autowired;
导入org.springframework.mock.web.MockHttpServletRequest;
导入org.springframework.mock.web.MockHttpSession;
导入org.springframework.stereotype.Component;
导入org.springframework.test.web.servlet.MockMvc;
导入org.springframework.test.web.servlet.ResultActions;
导入org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
导入org.springframework.test.web.servlet.setup.MockMvcBuilders;
导入org.springframework.web.context.WebApplicationContext;
导入javax.servlet.Filter;
导入静态com.condix.SessionLogoutRequestBuilder.sessionLogout;
导入静态org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
导入静态org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
导入静态org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
导入静态org.springframework.security.test.web.servlet.setup.SecurityMockMVCConfiguers.springSecurity;
导入静态org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
导入静态org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
导入静态org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@组成部分
公共类SessionBasedMockMvc{
私有静态最终字符串HOME_PATH=“/”;
私有静态最终字符串LOGOUT_PATH=“/login?LOGOUT”;
@自动连线
私有WebApplicationContext WebApplicationContext;
@自动连线
私有过滤器springSecurityFilterChain;
私有MockMvc-MockMvc;
公共MockMvc createSessionBasedMockMvc(){
最终MockHttpServletRequestBuilder defaultRequestBuilder=get(“/dummy path”);
this.mockMvc=MockMvcBuilders.webAppContextSetup(this.webApplicationContext)
.defaultRequest(defaultRequestBuilder)
.alwaysDo(结果->setSessionBackOnRequestBuilder(defaultRequestBuilder,result.getRequest())
.apply(springSecurity(springSecurityFilterChain))
.build();
返回此.mockMvc;
}
public void performLogin(最终字符串用户名、最终字符串密码)引发异常{
final ResultActions ResultActions=this.mockMvc.perform(formLogin().user(username).password(password));
此.assertSuccessLogin(resultActions);
}
public void performLogout()引发异常{
final ResultActions ResultActions=this.mockMvc.perform(sessionLogout());
此.assertSuccessLogout(结果);
}
私有MockHttpServletRequestSetSessionBackOnRequestBuilder(最终MockHttpServletRequestBuilder requestBuilder,
最终MockHttpServletRequest(请求){
session((MockHttpSession)request.getSession());
返回请求;
}
私有void assertSuccessLogin(最终结果ResultActions ResultActions)引发异常{
resultActions.andExpect(状态().isFound())
.andExpect(已验证()
.andExpect(重定向到URL(主路径));
}
私有void资产成功注销(最终结果ResultActions ResultActions)引发异常{
resultActions.andExpect(状态().isFound())
.andExpect(未经身份验证的())
.andExpect(重定向到URL(注销路径));
}
}
因为默认的LogoutRequestBuilder
不支持会话,我们需要创建另一个注销请求生成器
import org.springframework.beans.Mergeable;
导入org.springframework.mock.web.MockHttpServletRequest;
导入org.springframework.mock.web.MockHttpSession;
导入org.springframework.test.util.ReflectionTestUtils;
导入org.springframework.test.web.servlet.request.configurableMartRequestBuilder;
导入org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
导入org.springframework.test.web.servlet.request.RequestPostProcessor;
导入org.springframework.util.Assert;
导入org.springframework.util.StringUtils;
导入javax.ser
mockMvc.perform(get("your/url/{id}", 5).with(user("anyUserName")))
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
WithSecurityContextTestExcecutionListener.class})
@WithMockUser
public class WithMockUserTests {
...
}