Spring 安全,测试 MVC 和模拟服务
Spring security, test MVC and mock services
我想测试我的控制器,它有 @PreAuthorize
还有我想模拟的服务
PlayerController.java
@RestController
@RequestMapping(value = "/player")
public class PlayerController {
@Autowired
private PlayerService playerService;
@PreAuthorize("hasAuthority('ADMIN')")
@RequestMapping(value = "/all", method = RequestMethod.GET, produces = "application/json")
public
@ResponseBody
ResponseEntity<List<String>> loadByAdmin()
throws Exception {
return new ResponseEntity<>(playerService.getPlayers(), HttpStatus.OK);
}
}
PlayerServiceImpl.java
@Service
public class PlayerServiceImpl implements PlayerService{
@Autowired
private PlayerRepo playerRepo;
@Transactional(readOnly = true)
public List<String> getPlayers()() {
return playerRepo.findAll();
}
}
首先尝试:在这种情况下 - 测试有效,但如您所见,authority
是 SOMEONE
,因此它应该失败,因为只访问权限 ADMIN
。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {WebAppConfig.class, SecurityConfiguration.class})
public class PlayerControllerTest {
private MockMvc mockMvc;
@Autowired
private FilterChainProxy springSecurityFilterChain;
@Mock
private PlayerService playerService;
@InjectMocks
private PlayerController playerController;
@Test
public void loadByAdmin()
throws Exception {
Player player = new player();
when(playerService.getPlayers()).thenReturn(Collections.singletonList(player));
mockMvc.perform(get("/circuit/all").with(user("adm").password("123")
.authorities(new SimpleGrantedAuthority("SOMEONE"))) //not failed
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(playerService, times(1)).getPlayers();
verifyNoMoreInteractions(playerService);
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(playerController)
.apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain))
.build();
}
第二次尝试:所以我尝试了另一种方法,它适用于不同的权限,但在这种情况下我不能模拟 PlayerService
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {WebAppConfig.class, SecurityConfiguration.class})
public class PlayerControllerTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@Mock
private PlayerService playerService;
@InjectMocks
private PlayerController playerController;
@Test
public void loadByAdmin()
throws Exception {
Player player = new player();
when(playerService.getPlayers()).thenReturn(Collections.singletonList(player)); //not mocked
mockMvc.perform(get("/circuit/all").with(user("adm").password("123")
.authorities(new SimpleGrantedAuthority("ADMIN")))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(playerService, times(1)).getPlayers(); //no interaction
verifyNoMoreInteractions(playerService); //no interaction
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mockMvc.webAppContextSetup(wac)
.apply(springSecurity())
.build();
}
那么,我可以为模拟 PlayerService
和测试授权做些什么?
您能向我们展示 PlayerService 实现吗?
您也可以尝试@Autowire on playerService
并在setUp方法中添加一个播放器,对具有管理员权限的播放器进行检查,在@After中删除该播放器。由于这是一个集成测试,@Autowire 应该可以工作。
已反射解决
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {WebAppConfig.class})
public class PlayerControllerTest {
private MockMvc mockMvc;
@Mock
private PlayerService playerService;
@Autowired
private PlayerController playerController;
@Autowired
private FilterChainProxy springSecurityFilterChain;
@Test
public void loadByAdmin()
throws Exception {
Player player = new player();
when(playerService.getPlayers()).thenReturn(Collections.singletonList(player)); //success
mockMvc.perform(get("/circuit/all").with(user("adm").password("123")
.authorities(new SimpleGrantedAuthority("ADMIN")))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(playerService, times(1)).getPlayers(); //was called
verifyNoMoreInteractions(playerService);
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(playerController)
.apply(springSecurity(springSecurityFilterChain)).build();
ReflectionTestUtils.setField(playerController, "playerService", playerService);
}
我想测试我的控制器,它有 @PreAuthorize
还有我想模拟的服务
PlayerController.java
@RestController
@RequestMapping(value = "/player")
public class PlayerController {
@Autowired
private PlayerService playerService;
@PreAuthorize("hasAuthority('ADMIN')")
@RequestMapping(value = "/all", method = RequestMethod.GET, produces = "application/json")
public
@ResponseBody
ResponseEntity<List<String>> loadByAdmin()
throws Exception {
return new ResponseEntity<>(playerService.getPlayers(), HttpStatus.OK);
}
}
PlayerServiceImpl.java
@Service
public class PlayerServiceImpl implements PlayerService{
@Autowired
private PlayerRepo playerRepo;
@Transactional(readOnly = true)
public List<String> getPlayers()() {
return playerRepo.findAll();
}
}
首先尝试:在这种情况下 - 测试有效,但如您所见,authority
是 SOMEONE
,因此它应该失败,因为只访问权限 ADMIN
。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {WebAppConfig.class, SecurityConfiguration.class})
public class PlayerControllerTest {
private MockMvc mockMvc;
@Autowired
private FilterChainProxy springSecurityFilterChain;
@Mock
private PlayerService playerService;
@InjectMocks
private PlayerController playerController;
@Test
public void loadByAdmin()
throws Exception {
Player player = new player();
when(playerService.getPlayers()).thenReturn(Collections.singletonList(player));
mockMvc.perform(get("/circuit/all").with(user("adm").password("123")
.authorities(new SimpleGrantedAuthority("SOMEONE"))) //not failed
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(playerService, times(1)).getPlayers();
verifyNoMoreInteractions(playerService);
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders
.standaloneSetup(playerController)
.apply(SecurityMockMvcConfigurers.springSecurity(springSecurityFilterChain))
.build();
}
第二次尝试:所以我尝试了另一种方法,它适用于不同的权限,但在这种情况下我不能模拟 PlayerService
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {WebAppConfig.class, SecurityConfiguration.class})
public class PlayerControllerTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext wac;
@Mock
private PlayerService playerService;
@InjectMocks
private PlayerController playerController;
@Test
public void loadByAdmin()
throws Exception {
Player player = new player();
when(playerService.getPlayers()).thenReturn(Collections.singletonList(player)); //not mocked
mockMvc.perform(get("/circuit/all").with(user("adm").password("123")
.authorities(new SimpleGrantedAuthority("ADMIN")))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(playerService, times(1)).getPlayers(); //no interaction
verifyNoMoreInteractions(playerService); //no interaction
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mockMvc.webAppContextSetup(wac)
.apply(springSecurity())
.build();
}
那么,我可以为模拟 PlayerService
和测试授权做些什么?
您能向我们展示 PlayerService 实现吗?
您也可以尝试@Autowire on playerService
并在setUp方法中添加一个播放器,对具有管理员权限的播放器进行检查,在@After中删除该播放器。由于这是一个集成测试,@Autowire 应该可以工作。
已反射解决
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {WebAppConfig.class})
public class PlayerControllerTest {
private MockMvc mockMvc;
@Mock
private PlayerService playerService;
@Autowired
private PlayerController playerController;
@Autowired
private FilterChainProxy springSecurityFilterChain;
@Test
public void loadByAdmin()
throws Exception {
Player player = new player();
when(playerService.getPlayers()).thenReturn(Collections.singletonList(player)); //success
mockMvc.perform(get("/circuit/all").with(user("adm").password("123")
.authorities(new SimpleGrantedAuthority("ADMIN")))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
verify(playerService, times(1)).getPlayers(); //was called
verifyNoMoreInteractions(playerService);
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(playerController)
.apply(springSecurity(springSecurityFilterChain)).build();
ReflectionTestUtils.setField(playerController, "playerService", playerService);
}