27 Apr 2009 waffel   » (Journeyer)

How to test spring session or request scope beans


Often you need test cases where you want to use spring configured beans from a existing spring configuration instead of writing mock objects.

In such cases you can use the spring ContextConfiguration class annotation to load your spring configurations. For test cases you may also extend the AbstractTestNGSpringContextTests which gives you nice test support facilities.

But how to test beans which using special scopes like session or request?

The AbstractTestNGSpringContextTests does not provide support to test scoped beans.

Our test module provides a SimpleMapScope implementation, which can be used for scoped beans. There is also a spring configuration for the scopes request and session: session-request-testscopes.xml which can be used as a ContextConfiguration location.

For example you can write follow simple test case:


....

@ContextConfiguration(locations = {"/org/waffel/test/session-request-testscopes.xml",
  "/org/waffel/my-app-beans.xml})
public class SimpleScopeBeansTest extends AbstractTestNGSpringContextTests {

  /**
   * A bean which is in scope session.
   */
  @Autowired
  @Qualifier("sessionScopedBean")
  private MyBean sessionScopedBean;

  @Test
  public void testAccessToBean() {
    AssertNotNull(sessionScopedBean);
  }

....

This test uses the test scope spring configuration and another spring configuration, where the sessionScopedBean is in scope session. With the autowired feature, you have instantly access to the bean. Also if the bean is in session or request scope.

The SimpleMapScope implementation:


package org.waffel.test.spring;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;

/**
 * This simple scope implementation uses internal a {@link Map} to hold objects
 * in the scope. This scope implementation can be used for testing beans which
 * wants to be stayed for example in session or request scope.
 * <p>
 * To use this scope in your test cases, simple configure a
 * {@link org.springframework.beans.factory.config.CustomScopeConfigurer} with
 * the required scope name:
 *
 * <pre>
 * &lt;bean class=&quot;org.springframework.beans.factory.config.CustomScopeConfigurer&quot;&gt;
 *   &lt;property name=&quot;scopes&quot;&gt;
 *     &lt;map&gt;
 *       &lt;entry key=&quot;session&quot;&gt;
 *         &lt;bean class=&quot;com.siemens.spice.dc.spring.SessionScope&quot; /&gt;
 *       &lt;/entry&gt;
 *     &lt;/map&gt;
 *   &lt;/property&gt;
 * &lt;/bean&gt;
 * </pre>
 *
 * Because the
 * {@link org.springframework.beans.factory.config.CustomScopeConfigurer} is a
 * {@link org.springframework.beans.factory.config.BeanPostProcessor} all
 * requested beans for the scope loaded with that post processor if the
 * registered scope match.
 * </p>
 *
 * @author waffel
 */
public class SimpleMapScope implements Scope {

  /**
   * This map contains for each bean name or ID the created object. The objects
   * are created with a spring object factory.
   */
  private final Map<string , Object> objectMap = new HashMap</string><string , Object>();

  /**
   * {@inheritDoc}
   */
  public Object get(final String theName, final ObjectFactory theObjectFactory) {
    Object object = objectMap.get(theName);
    if (null == object) {
      object = theObjectFactory.getObject();
      objectMap.put(theName, object);
    }
    return object;
  }

  /**
   * {@inheritDoc}
   */
  public String getConversationId() {
    return null;
  }

  /**
   * {@inheritDoc}
   */
  public void registerDestructionCallback(final String theName, final Runnable theCallback) {
    // nothing to do ... this is optional and not required
  }

  /**
   * {@inheritDoc}
   */
  public Object remove(final String theName) {
    return objectMap.remove(theName);
  }

}

The session-request-testscopes.xml source:


< ?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

  <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
    <property name="scopes">
      <map>
        <entry key="session">
          <bean class="org.waffel.test.spring.SimpleMapScope" />
        </entry>
        <entry key="request">
          <bean class="org.waffel.test.spring.SimpleMapScope" />
        </entry>
      </map>
    </property>
  </bean>

</beans>

Another approach can be found in ahöhma’s weblog.

Posted in spring Tagged: java, request, scope, session, singleton, spring, test, TestNG, unit

Syndicated 2009-04-27 11:45:59 from waffel's Weblog

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!