Search code examples
spring-bootunit-testingjunitmockito

How to mock Spring Boot Session and SecurityContext for testing purpose


It is Spring Boot project. It uses SecurityContext.

Most of its Rest controller and service, depend on the role of its logged in user, for validation purpose. So during testing, I need a user to login.

Please inform me unit testing code example, for Spring boot, that involve login user process.

@RunWith(PowerMockRunner.class)
@PrepareForTest({SecurityContextHolder.class,AuthenticationManager.class,UserRepository.class,UserCreationRequestRepository.class,        PasswordEncoder.class,AuthorityRepository.class,CacheManager.class,POMasterCompanyRepository.class,BranchRepository.class})
public class BOAuthControllerTest {

@Autowired
private WebApplicationContext context;

@Mock
private AuthenticationManager authenticationManager;

@Mock
private UserRepository userRepository;
@Mock
private UserCreationRequestRepository userCreationRequestRepository;
@Mock
private PasswordEncoder passwordEncoder;
@Mock
private AuthorityRepository authorityRepository;
@Mock
private CacheManager cacheManager;
@Mock
private POMasterCompanyRepository poMasterCompanyRepository;
@Mock
private BranchRepository branchRepository;
private UserService userService;

private MockMvc mockMvc;

@Before
public void setup() {

    userService = new UserService(userRepository, passwordEncoder, authorityRepository, cacheManager, userCreationRequestRepository,
            poMasterCompanyRepository,branchRepository);

    UsernamePasswordAuthenticationToken authenticationToken =
            new UsernamePasswordAuthenticationToken("admin","admin");
    Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
    SecurityContextHolder.getContext().setAuthentication(authentication);
    SecurityContext securityContext = new SecurityContextImpl();
    securityContext.setAuthentication(authentication);

            System.out.println(authenticationToken==null?"null":"not null");
    System.out.println(authenticationManager==null?"null":"not null");
    System.out.println(authentication==null?"null":"not null");
    System.out.println(SecurityContextHolder.getContext()==null?"null":"not null");
    System.out.println(SecurityContextHolder.getContext().getAuthentication()==null?"null":"not null");
    System.out.println(SecurityContextHolder.getContext().getAuthentication().getName());
    System.out.println(securityContext.getAuthentication().getName());

    PowerMockito.mockStatic(SecurityContextHolder.class);
    when(SecurityContextHolder.getContext()).thenReturn(securityContext);

    System.out.println(userService.getUserWithAuthorities().isPresent());
}

@Test
public void loginAvailableForAll() throws Exception {

    System.out.println(userService.getUserWithAuthorities().isPresent());

}

}


Solution

  • You can use PowerMock to mock SecurityContextHolder. Example mocking SecurityContext to return a list of desired roles

        import org.junit.Test
        import org.junit.runner.RunWith
        import org.powermock.api.mockito.PowerMockito
        import org.powermock.core.classloader.annotations.PrepareForTest
        import org.powermock.modules.junit4.PowerMockRunner
        import org.springframework.security.authentication.TestingAuthenticationToken
        import org.springframework.security.core.authority.SimpleGrantedAuthority
        import org.springframework.security.core.context.SecurityContext
        import org.springframework.security.core.context.SecurityContextHolder
        import org.springframework.security.core.context.SecurityContextImpl
    
        import static org.mockito.Mockito.when
    
        @RunWith(PowerMockRunner.class)
        @PrepareForTest([SecurityContextHolder.class])
        class Dummy {
    
        @Test
        void isAdminUser(){
            String roleList = 'ROLE_ADMIN'
            PowerMockito.mockStatic(SecurityContextHolder)
            when(SecurityContextHolder.getContext()).thenReturn(getDesiredSecurityContext(roleList))
            //assertTrue()
        }
    
        // This will create a security context with the list of roles required
        private SecurityContext getDesiredSecurityContext(String roles){
            List<String> roleList = roles.split(',')
            List<SimpleGrantedAuthority> authorities = roleList.collect { new SimpleGrantedAuthority(it)}
            SecurityContext securityContext = new SecurityContextImpl()
            securityContext.setAuthentication(new TestingAuthenticationToken(null,null,authorities))
            return securityContext
        }
    
      }