Tuesday, September 25, 2007

Testing HTTPS Secured Actions with StrutsTestCase

If you have secured some Struts actions using SSLEXT's Struts plugin (org.apache.struts.action.SecurePlugIn) you will have to invoke the action over https, else SSLEXT will redirect to the configured HTTPS port.

So in order to test secured actions using MockStruts test cases you need to inform SecurePlugIn that the request came over https. This is quite easy as the HttpServletRequestSimulator class that's used by MockStruts has a setScheme method. All you have to do is set the scheme to HTTPS in the inherited request object before calling the actionPerform method in the test class.

e.g.


public class LoginTest extends MockStrutsTestCase {
public void testlogin() {
setConfigFile("/WEB-INF/struts-config.xml");
setRequestPathInfo("/login");
addRequestParameter("username", "test");
addRequestParameter("password", "test1234");

//set the request's scheme to HTTPS
request.setScheme("HTTPS");
//invoke action
actionPerform();

verifyNoActionErrors();
verifyForward("success");
}
}

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

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.