2

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

..

Community
  • 1
  • 1
grepit
  • 21,260
  • 6
  • 105
  • 81
  • 1
    You should decompose your 'if' statement into intermediate instructions (with intermediate local variables), one on each line. Then you could see on what object the NPE occurs. However I'm almost certain that it comes from the authentication that is not mocked. – superbob Mar 13 '15 at 19:24

2 Answers2

3

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);
}
superbob
  • 1,628
  • 13
  • 24
  • There was no need to change the main code but I think your answer helped me to narrow down what needed to be done. So, I want to thank you for spending the time and working on this and I will give you a 1+ because of helping and providing a solution that guided me to solve it. Thanks – grepit Mar 14 '15 at 18:19
2

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

    }
grepit
  • 21,260
  • 6
  • 105
  • 81