SecurityContextHolder在junit tests

时间:2017-12-26 01:24:03

标签: spring

我尝试了两种方法来进行控制器单元测试。

M1:

@RunWith(SpringRunner.class)
@SpringBootTest
public class WorkOrderControllerTest {
    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    @WithUserDetails(value="Tom", userDetailsServiceBeanName = "customizedUserDetailsService")
    public void testGetworkList() {
        URI uri = URI.create("/foo");
        ResponseEntity exchange = testRestTemplate.getForEntity(uri, String.class);
    }
}

M2:

@Test
public void testGetworkList() throws Exception {

    List<GrantedAuthority> list = ...;
    String uri = "/foo";

    ResultActions perform = mvc.perform(post(uri).with(csrf().asHeader()).with(user("Tom").roles("CP").authorities(list)));
}

@Before
public void setup() {
    mvc = MockMvcBuilders.webAppContextSetup(context)
        .apply(SecurityMockMvcConfigurers.springSecurity()) 
        .build();
}

它们都执行正确的登录(弹簧安全性会阻止任何请求),然后进入控制器方法。对于M1,控制器后面的语句:SecurityContextHolder.getContext().getAuthentication(),应包含正确的SecurityUser,返回“匿名”。对于M2:返回弹簧用户pojo。因为我必须使用customizedUserDetailsService bean来生成自定义的用户pojo。这是 Spring bug 吗?我发现更多:在M1中,SecurityContextHolder setContext被调用两次,第一个上下文参数是正确的,包含我自己的用户pojo,而第二个上下文参数是错误的,我相信这就是导致“匿名”的原因。

一位关于GH的人评论说我混淆了集成测试和模拟测试,@WithUserDetails用于模拟测试。所以我使用了@WithUserDetailsMockMvc(M1和M2的组合),结果显示它实现了我的目标:

  1. 用户登录,通过customizedUserDetailsS​​ervice bean传递。
  2. SecurityContextHolder返回登录用户。
  3. 代码:

    @Test
    @WithUserDetails(value="Tom", userDetailsServiceBeanName = "customizedUserDetailsService")
    public void testGetworkList() {
        String uri = ...;
        ResultActions result = mvc.perform(post(uri).with(csrf()));
    }
    

1 个答案:

答案 0 :(得分:0)

,这不是错误;这是正确的SecurityContextHolder是一个单例 bean,但在 JUnit 测试中它是线程范围的而不是会话范围。并且使用JUnit,您需要先设置一些东西。

有一些方法,你可以使用Mokito并为SecurityContext设置一个SecurityContextHolder对象:

Authentication authentication = Mockito.mock(Authentication.class);
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
//Now you can access the real user loggedin