34

I have a session scoped bean which holds user data per http session. I would like to write a Junit test case to test the session scoped bean. I would like to write the test case such that it can prove that the beans are getting created per session. Any pointer as how to write such Junit test case?

Laplas
  • 687
  • 1
  • 7
  • 10
Shamik
  • 6,938
  • 11
  • 55
  • 72

3 Answers3

31

I came across this simpler approach, thought I might as well post here in case others need it.

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
        <map>
            <entry key="session">
                <bean class="org.springframework.context.support.SimpleThreadScope"/>
            </entry>
        </map>
    </property>
</bean>

With this approach, you don't have to mock any request/session objects.

Source: http://tarunsapra.wordpress.com/2011/06/28/junit-spring-session-and-request-scope-beans/

Update for spring 5.x (works in spring 5.3.22, in a JUnit5 test, annotated by @ExtendWith(SpringExtension.class) ): The same bean definitions by annotations. Place this code somewhere in a spring configuration class:

/**
 * Used in CustomScopeConfigurer bean below
 *
 * @return
 */
@Bean
public static SimpleThreadScope simpleThreadScope()
{
    return new SimpleThreadScope();
}

/**
 * This bean is needed in order to mimic spring's SessionScope
 *
 * @param aSimpleThreadScope
 * @return
 */
@Bean
public static CustomScopeConfigurer customScopeConfigurer(SimpleThreadScope aSimpleThreadScope)
{
    CustomScopeConfigurer result = new CustomScopeConfigurer();
    result.addScope( "session", aSimpleThreadScope );
    return result;
}
Heri
  • 4,368
  • 1
  • 31
  • 51
kctang
  • 10,894
  • 8
  • 44
  • 63
  • The same applies to 'request' scope, just use key='request' for the request scoped beans. – Zeus Sep 23 '16 at 20:46
30

In order to use request and session scopes in unit test you need to:

  • register these scopes in application context
  • create mock session and request
  • register mock request via RequestContextHolder

Something like this (assume that you use Spring TestContext to run your tests): abstractSessionTest.xml:

<beans ...>
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="session">
                    <bean class="org.springframework.web.context.request.SessionScope" />
                </entry>
                <entry key="request">
                    <bean class="org.springframework.web.context.request.RequestScope" />
                </entry>
            </map>
        </property>
    </bean>
</beans>

.

@ContextConfiguration("abstractSessionTest.xml")
public abstract class AbstractSessionTest {
    protected MockHttpSession session;
    protected MockHttpServletRequest request;

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

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

    protected void startRequest() {
        request = new MockHttpServletRequest();
        request.setSession(session);
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
    }

    protected void endRequest() {
        ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).requestCompleted();
        RequestContextHolder.resetRequestAttributes();
        request = null;
    }
}

Now you can use these methods in your test code:

startSession();
startRequest();
// inside request
endRequest();
startRequest();
// inside another request of the same session
endRequest();
endSession();
axtavt
  • 239,438
  • 41
  • 511
  • 482
12

Spring 3.2 and newer provides support for session/request scoped beans for integration testing

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
@WebAppConfiguration
public class SampleTest {

    @Autowired WebApplicationContext wac;

    @Autowired MockHttpServletRequest request;

    @Autowired MockHttpSession session;    

    @Autowired MySessionBean mySessionBean;

    @Autowired MyRequestBean myRequestBean;

    @Test
    public void requestScope() throws Exception {
        assertThat(myRequestBean)
           .isSameAs(request.getAttribute("myRequestBean"));
        assertThat(myRequestBean)
           .isSameAs(wac.getBean("myRequestBean", MyRequestBean.class));
    }

    @Test
    public void sessionScope() throws Exception {
        assertThat(mySessionBean)
           .isSameAs(session.getAttribute("mySessionBean"));
        assertThat(mySessionBean)
           .isSameAs(wac.getBean("mySessionBean", MySessionBean.class));
    }
}

References:

Community
  • 1
  • 1
MariuszS
  • 30,646
  • 12
  • 114
  • 155
  • 2
    After adding WebAppConfiguration I had an initializationError error that I solved adding the servlet-api to the pom file as stated here: http://nickebbitt.wordpress.com/2013/12/20/spring-3-2-mvc-unit-testing-initializationerror-using-webappconfiguration/ – borjab Jun 09 '14 at 16:29
  • Tipp: do not use \@WebAppConfiguration in combination with \@IntegrationTest. Does not work for me – Simon Ludwig Dec 01 '16 at 18:57