【问题标题】:NullPointerException when Spring SecurityContextHolder is called调用 Spring SecurityContextHolder 时出现 NullPointerException
【发布时间】:2015-05-16 09:53:45
【问题描述】:

我一直在尝试为以下代码行编写测试用例,但我不断收到 java.lang.NullPointerException,我试图遵循/复制其他人在这里提出的建议 Unit testing with Spring Security 但我没有运气。有人可以帮助我更好地识别或提示我需要做什么。 (我为此使用了 mockito)

代码:

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

测试用例:

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

..

【问题讨论】:

  • 您应该将您的“if”语句分解为中间指令(带有中间局部变量),每行一个。然后你可以看到 NPE 发生在哪个对象上。但是我几乎可以肯定它来自未模拟的身份验证。

标签: java spring mockito


【解决方案1】:

您的测试有 2 个问题:

  1. 你必须模拟每个“级别”的方法调用,你应该模拟:

    • SecurityContext.getAuthentication()
    • Authentication.getPrincipal()
    • Principal.equals()
  2. 但是,您不能模拟 .equals(),请参阅 Mockito FAQ - limitationsMockito - Issue 61

您必须以不同的方式设计代码/测试。例如,将“用户”主体传递给您的方法参数,并使 Authentication.getPrincipal() 返回另一个(它们会有所不同,从而使等号返回 false):

代码

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

测试

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

【讨论】:

  • 没有必要更改主代码,但我认为您的回答帮助我缩小了需要做的事情。所以,我要感谢你花时间和工作,我会给你一个 1+,因为帮助并提供了一个指导我解决它的解决方案。谢谢
【解决方案2】:

为了完成这项工作,我做了一些重要的事情,希望这对其他人也有帮助。

  1. 使用了@InjectMocks:
     
    @InjectMocks
    private static YourMainController controller;
    
  2. 模拟了将添加到上述主模拟中的依赖项:
     
    @Mock SecurityContext securityContextMocked; @Mock Authentication authenticationMocked; @Mock Principal principal1;
  3. 将测试修改为如下所示,使其运行良好。
     
    @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();
 
 

    }

【讨论】:

    猜你喜欢
    • 2020-10-30
    • 2013-12-29
    • 2015-02-13
    • 2012-01-21
    • 2012-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多