Friday, September 7, 2007

Speed up MockStruts Test Execution by Caching Spring Context

If you are using MockStruts to test your Struts/Spring application most of your test execution time would be spent on initializing or trying to initialize the Spring context for each test method.

This is true if you use Spring's ContextLoaderPlugIn, where it tries to initialize a custom spring context using the parent context.

Spring will look for the parent context in the ServletContext object where it store it. Since MockStruts will create a new ServletContext for each test method Spring will try to create the context each time. This results in addition of about 4 second per test method (on my workstation).

Note: I'm using MappingDispatchAction with multiple actions in a single Action class, therefore I have mutiple test methods in a single test class too.

The above 4 second penalty per test method can be removed by simply caching and storing the Spring context in ServletContext object before each test execution. This reduced the execution time of the whole test suite drastically in the application I was working on.

In order to achieve the above I used a base class extending MockStrutsTestCase as shown below and used it as the parent class for all the Struts test cases


import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import servletunit.struts.MockStrutsTestCase;

public abstract class BaseStrutsTestCase extends MockStrutsTestCase {

/** Spring context */
private static ApplicationContext applicationContext;

/**
* Setup Spring context
*
* @throws Exception
* exception
*/
protected void setUp() throws Exception {
super.setUp();

if (applicationContext == null) {
// this is the first time. Initialize the Spring context.
applicationContext = (new ContextLoader()).initWebApplicationContext(getRequest().getSession()
.getServletContext());
} else {
// Spring context is already initialized. Set it in servlet context
// so that Spring's ContextLoaderPlugIn will not initialize it again
getRequest().getSession().getServletContext().setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, applicationContext);
}
}

/**
* Returns the Spring application context
*
* @return initialized Spring application context
*/
public ApplicationContext getApplicationContext() {
return applicationContext;
}

}


Also remember to set forkMode to perBatch or once in ants junit task as shown below if you have set the fork attribute to true.


<junit fork="true" forkmode="once" haltonfailure="">
...

</junit>

Don' forget to click the +1 button below if this post was helpful.

1 comment:

Tanika Co Valda said...

Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a Java developer learn from Java Training in Chennai. or learn thru Java EE Online Training from India . Nowadays Java has tons of job opportunities on various vertical industry.