我尝试了两种方法来进行控制器单元测试。
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
用于模拟测试。所以我使用了@WithUserDetails
和MockMvc
(M1和M2的组合),结果显示它实现了我的目标:
代码:
@Test
@WithUserDetails(value="Tom", userDetailsServiceBeanName = "customizedUserDetailsService")
public void testGetworkList() {
String uri = ...;
ResultActions result = mvc.perform(post(uri).with(csrf()));
}
答案 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