简体   繁体   中英

Spring security, test MVC and mock services

I want to test my controller, which has @PreAuthorize and also it has service which i want to mock

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();
  }
}

First try: In this case - test works, but as you can see authority is SOMEONE so it should be fail because only authority ADMIN is accessed.

@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();
}

Second try: So i try another method, it works right for different authorities, but in this case i can't to mock 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();
}

So, what can i do for mock PlayerService and test Authorization?

Can you show us the PlayerService impl?

Also you may try to @Autowire on playerService and add a palyer on setUp method, do the check on players with admin authority, in @After remove that player. Since this is an integration test @Autowire should work.

It has been solved with reflection

@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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM