【问题标题】:Test a Spring Controller with JUnit that depends of Spring Security使用依赖于 Spring Security 的 JUnit 测试 Spring Controller
【发布时间】:2016-04-21 19:40:41
【问题描述】:

我有一个 Spring 应用程序,我正在构建 JUnit 测试来测试某个 Controller

问题是在Controller里面我调用了这个代码:

final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
final String userName = authentication.getName();

换句话说,我需要在调用此Controller 之前进行身份验证。我用这段代码写了一个JUnit 测试:

private MockMvc mockMvc;

    @Test
    public void getPageTest() throws Exception{
        final ProcessFileController controller = new ProcessFileController();
        mockMvc = standaloneSetup(controller).build();

    mockMvc.perform(get(URI.create("/processFile.html")).sessionAttr("freeTrialEmailAddress", "")).andExpect(view().name("processFile"));
        }

当我运行它时,它会在final String userName = authentication.getName(); 上给我一个NullPointerException,因为我的authenticationnull,因为我没有登录。

问题是:有没有办法模拟身份验证?欢迎所有想法。

谢谢。

【问题讨论】:

  • 你为什么要手动而不是使用@AuthenticationPrincipal
  • chrylis,该架构不是为使用@AuthenticationPrincipal 而设计的,我需要一个想法,一种方法来处理我现在拥有的当前架构。谢谢你的回答。

标签: java spring spring-mvc junit spring-security


【解决方案1】:

Spring Security 版本 4 对此进行了一些巧妙的改进。

首先确保您在类路径中有用于测试的测试框架,使用 Maven,它看起来像:

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <version>4.0.4.RELEASE</version>
  <scope>test</scope>
</dependency>

有用的导入:

import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;

测试设置:

mockMvc = webAppContextSetup(applicationContext).apply(springSecurity()).build();

(我认为您需要 WebApplicationContext 而不是单个控制器。)

然后测试类似:

mockMvc.perform(get(...).with(user("username").roles("USER"))).andExpect(...);

【讨论】:

    【解决方案2】:

    理想情况下,您应该使用@AuthenticationPrincipal,但如果这不是一个选项,您需要使用Authentication 实例设置SecurityContext,然后该实例将在测试中可用。

    您可以在帮助类中使用静态方法来执行此操作。

    public static void setupSecurityContext(String username, String password, String... groups)
    {
      List<GrantedAuthority> authorities = new ArrayList<>();
      for (String group : groups)
      {
        authorities.add(new SimpleGrantedAuthority(group));
      }
    
      UserDetails user = new UserDetails(username, password, authorities);
      UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user, password);
      SecurityContextHolder.getContext().setAuthentication(token);
    }
    

    然后在测试中你可以简单地调用

    SecurityHelper.setupSecurityContext("user", "password", "g1", "g2");

    【讨论】:

    • 在测试后重置SecurityContextHolder.getContext().setAuthentication(token) 会很好,以使测试独立。由于此 SecurityContextHolder 是单例,因此您在所有单元测试之间共享相同的信息。
    • @Dherik 您可以在 \@After 方法中设置为 null。
    • 哦,是的,我只是警告这一点,因为这是人们在测试中使用 Singleton 时的常见问题,并且可能会在测试期间导致奇怪的问题
    猜你喜欢
    • 2013-12-21
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    • 2016-07-16
    • 2018-12-10
    • 2018-06-10
    • 1970-01-01
    相关资源
    最近更新 更多