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.

No comments: