如何在 Spring Junit 中创建会话

Posted

技术标签:

【中文标题】如何在 Spring Junit 中创建会话【英文标题】:How to create session in Spring Junit 【发布时间】:2015-01-22 01:11:26 【问题描述】:

我有这样的层:

Spring Controller -> 服务层 -> Dao 层 (JPA)。

我想编写服务和控制器的测试用例。在另一个Junit会调用控制器,控制器会调用服务,服务层获取数据库信息等等。

在这种情况下我不想模拟,我只想编写junit测试用例(我必须调用服务并且服务必须从数据库中获取真实数据)。

我只有一个问题,服务层从会话中获取用户 ID。我得到了自动装配注释的会话。如何在测试用例期间创建假会话?

p.s 我认为 mock 不适合我...因为我不会模拟我的服务,我想用真实的 db 数据创建真正的控制器调用...

【问题讨论】:

它是一个会话范围的 bean 保存用户的数据吗? 你的服务层组件是session-scoped bean吗? 另外,您有兴趣使用Spring MVC Test Framework吗? 【参考方案1】:

我们可以使用模拟。这是代码示例。

private MockMvc mockMvc;

        @Autowired
        private FilterChainProxy springSecurityFilterChain;

        @Autowired
        private WebApplicationContext wac;

        protected MockHttpSession session;

        protected MockHttpServletRequest request;

        @Before
        public void setup() 
            this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).addFilters(this.springSecurityFilterChain).build();
        

        @Test
        void test()
        // I log in and then returns session 
        HttpSession session = mockMvc.perform(post("/j_spring_security_check").param("NAME", user).param("PASSWORD", pass))
                    .andDo(print()).andExpect(status().isMovedTemporarily()).andReturn().getRequest().getSession();
        

我们也可以用这种方式,你只需调用startSession()方法,就会返回“当前”会话。

protected void startSession() 
        session = new MockHttpSession();
    

    protected void endSession() 
        session.clearAttributes();
        session = null;
    

    // we can create request too, just simple way
    protected void startRequest() 
        request = new MockHttpServletRequest();
        request.setSession(session);
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
    

【讨论】:

【参考方案2】:

你可以使用MockHttpSession:http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/mock/web/MockHttpSession.html

更多信息在这里: Spring mvc 3.1 integration tests with session support

【讨论】:

我不会嘲笑。因为然后我调用 this.mockMvc.perform(my controller),mock 不会调用我的服务层。这是我的问题,米 我的意思是我用mock的时候这个问题,所以我不会mock:***.com/questions/26508628/… 如果您将用户 ID 作为属性存储在会话中,您也可以在 MockHttpSession 上进行设置。然后,当您的代码使用该对象时,它将返回您想要的任何值。【参考方案3】:

一种选择是使用 SpEL 表达式将用户 ID(不是 HttpSession)注入您的服务组件。要实现正确的运行时行为,您必须确保您的服务组件是 AOP 范围的代理。

查看 Spring 参考手册的 "Testing request and session scoped beans" 部分了解更多信息。

问候,

Sam (spring-test 组件负责人)

【讨论】:

【参考方案4】:

我编写了以下函数来在使用 mongo 会话存储时创建“真实”会话。

private Session generateMongoHttpSession(final Role role, final Permission... permissions) 
  final Set<GrantedAuthority> authorities =
    role.getPermissions()
        .stream()
        .map(p -> new SimpleGrantedAuthority(p.toString()))
        .collect(Collectors.toSet());

  Arrays.stream(permissions)
    .forEach(p -> authorities.add(new SimpleGrantedAuthority(p.toString())));

  final UserDetails userDetails =
    new org.springframework.security.core.userdetails.User(
        "test-user-name", "test-password", true, true, true, true, authorities);

  final Authentication authentication =
    new UsernamePasswordAuthenticationToken(
        userDetails, userDetails.getPassword(), userDetails.getAuthorities());

  final UsernamePasswordAuthenticationToken authenticationToken =
    new UsernamePasswordAuthenticationToken(
          userDetails, authentication.getCredentials(), userDetails.getAuthorities());
  authenticationToken.setDetails(authentication.getDetails());

  final SecurityContextImpl context = new SecurityContextImpl();
  context.setAuthentication(authentication);

  final MongoExpiringSession session = mongoOperationsSessionRepository.createSession();
  session.setAttribute("SPRING_SECURITY_CONTEXT", context);
  session.setAttribute("sessionId", session.getId());
  mongoOperationsSessionRepository.save(session);

  return session;

【讨论】:

以上是关于如何在 Spring Junit 中创建会话的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security,JUnit:@WithUserDetails 用于在 @Before 中创建的用户

如何使用 JUnit 5 在 Kotlin 中创建 TestContainers 基测试类

如何在 jquery 中创建会话?

如何在 Swift 中创建 QuickBlox 会话 [关闭]

如何在无状态会话 bean 中创建多线程?

当 Rails 中的同一域上存在会话时,如何在 PHP 中创建会话?