grepit
grepit

Reputation: 22382

NullPointerException when Spring SecurityContextHolder is called

I have been trying to write a test case for the following line of code but I keep getting java.lang.NullPointerException, I have tried to follow/replicate what others have suggested here Unit testing with Spring Security but I have had no luck. Can someone please help me better identify or give me a hint what I need to do. (I'm using mockito for this)

Code:

if (SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals(user)) {
                continue;
            }

Test case:

@Test
public void testExpireAllSession() throws Exception {

        SecurityContext securityContext = Mockito.mock(SecurityContext.class);
        Mockito.when(securityContext.getAuthentication().getPrincipal().equals(any(Object.class))).thenReturn(false);
        SecurityContextHolder.setContext(securityContext);

       controller.theMEthodUnderTest();
}

..

Upvotes: 2

Views: 5011

Answers (2)

grepit
grepit

Reputation: 22382

Few important things I did to make this work and hope this helps others as well.

  1. Used the @InjectMocks :
     
    @InjectMocks
    private static YourMainController controller;
    
  2. Mocked the dependencies which would get added to the main mock above:
     
    @Mock SecurityContext securityContextMocked; @Mock Authentication authenticationMocked; @Mock Principal principal1;
  3. Modified the test to look like this and that made it work nicely.
     
    @Test

    public void testExpireAllSession() throws Exception {

    List mySessions = new ArrayList<>();
 
    Object principal="";

    Date aDate = new Date();
 

    SessionInformation sessionInformation = new SessionInformation(principal,”100000”,aDate);
 mySessions.add(sessionInformation);
 allUsers.add("Mike"); when(authenticationMocked.getPrincipal()).thenReturn(principal1);
when(securityContextMocked.getAuthentication()).thenReturn(authenticationMocked); SecurityContextHolder.setContext(securityContextMocked);
when(sessionRegistryMocked.getAllSessions(allUsers,false)).thenReturn(sessions); when(sessionRegistryMocked.getAllPrincipals()).thenReturn(allUsers); controller.expireAllSession(); verify(sessionRegistryMocked).getAllPrincipals();
 
 

    }

Upvotes: 2

superbob
superbob

Reputation: 1638

There are 2 problems with your test :

  1. You must mock each "level" of method calls, you should mock :

    • SecurityContext.getAuthentication()
    • Authentication.getPrincipal()
    • Principal.equals()
  2. But, you can't mock .equals(), see Mockito FAQ - limitations and Mockito - Issue 61.

You have to design your code/test differently. For example, pass a 'user' principal to your method arguments, and make Authentication.getPrincipal() return another one (they will be different, thus making the equals return false) :

Code

public void theMethod(Principal user) {
  ...
  if (SecurityContextHolder.getContext().getAuthentication().getPrincipal().equals(user)) {
    continue;
  }
  ...
}

Test

@Test public void testController() {
    SecurityContext securityContext = Mockito.mock(SecurityContext.class);
    Authentication authentication = Mockito.mock(Authentication.class);
    Principal principal1 = Mockito.mock(Principal.class);
    Principal principal2 = Mockito.mock(Principal.class);
    Mockito.when(authentication.getPrincipal()).thenReturn(principal1);
    Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
    SecurityContextHolder.setContext(securityContext);
    new Controller().theMethod(principal2);
}

Upvotes: 3

Related Questions