When creating unit tests for your Struts 2 application you'll want to be able to test certain aspects of the action class that normally require the action to be running within a Servlet container and the Struts 2 interceptors to have executed.  For example if your Struts 2 action class includes a validate method that checks the values of the instance fields populated by the user's input on a Struts 2 form, you need the interceptors to have run that get the user's form field input out of request scope and assign the form field values to the appropriate instance fields.

Struts 2 provides a JUnit plugin library that makes it easier to develop unit tests for testing your Struts 2 action classes.  This tutorial will provide an example of how to use the Struts 2 JUnit plugin.

This tutorial assumes the reader knows how to create a Struts 2 application and how to write unit tests using JUnit.

To use the Struts 2 JUnit plugin, you'll need to have the plugin's Jar file on your application's class path.  If you're using Maven you can add this dependency to your pom.xml.

Struts 2 JUnit Plugin Dependency
<dependency>
    <groupId>org.apache.struts</groupId>
    <artifactId>struts2-junit-plugin</artifactId>
    <version>STRUTS_VERSION</version>
</dependency>

Of course replace STRUTS_VERSION with the current Struts 2 version number.

For this tutorial we'll use the following Struts 2 ActionSupport class.

AccountAction.java
public class AccountAction extends ActionSupport {

	private static final long serialVersionUID = 1L;

	private static final Logger logger = Logger.getLogger( AccountAction.class.getName() );

	private Account accountBean;

	public String execute(){

		return SUCCESS;

	}

	public void validate(){

		logger.debug("In method validate. accountBean's state is " + accountBean );

		if ( accountBean.getUserName().length() == 0 ){

			addFieldError( "accountBean.userName", "User name is required." );

		}

		if ( accountBean.getUserName().length() < 5 ) {

			addFieldError( "accountBean.userName", "User name must be at least 5 characters long." );

		}

		if ( accountBean.getUserName().length() > 10 ) {

			addFieldError( "accountBean.userName", "User name cannot be at more than 10 characters long." );

		}


	}

	public Account getAccountBean() {
		return accountBean;
	}

	public void setAccountBean(Account accountBean) {
		this.accountBean = accountBean;
	}

}


The above action class is called after a user enters information on a create account form. Struts takes the user's input on the form fields and uses those values to populate the state of the Account object (accountBean).

Then the validate method is executed to check the values of the accountBean's instance fields against certain business rules (for example the length of the username cannot be more than 10).

To test the validate method we can use the Struts 2 JUnit plugin to simulate the Servlet container and Struts 2 framework. Our Junit test class just needs to extend the StrutsTestCase. The StrutsTestCase class is part of the Strut 2 JUnit Plugin library.

JUnit Test Case For Struts Action Class
public class TestAccountActionUsingStrutsTestCase extends StrutsTestCase {

    public void testUserNameErrorMessage() throws Exception {

    	request.setParameter("accountBean.userName", "Bruc");
    	request.setParameter("accountBean.password", "test");

    	ActionProxy proxy = getActionProxy("/createaccount");

    	AccountAction accountAction = (AccountAction) proxy.getAction();

        proxy.execute();

        assertTrue("Problem There were no errors present in fieldErrors but there should have been one error present", accountAction.getFieldErrors().size() == 1);
		assertTrue("Problem field account.userName not present in fieldErrors but it should have been",
				accountAction.getFieldErrors().containsKey("accountBean.userName") );

    }

    public void testUserNameCorrect() throws Exception {

    	request.setParameter("accountBean.userName", "Bruce");
    	request.setParameter("accountBean.password", "test");

    	ActionProxy proxy = getActionProxy("/createaccount");

    	AccountAction accountAction = (AccountAction) proxy.getAction();

        String result = proxy.execute();

        assertTrue("Problem There were errors present in fieldErrors but there should not have been any errors present", accountAction.getFieldErrors().size() == 0);
        assertEquals("Result returned form executing the action was not success but it should have been.", "success", result);

    }

}


The request object above is a MockHttpServletRequest provided by the StrutsTestCase class. We can use this mock Servlet Request object to set values on the request scope as if the user had typed those values into a Struts 2 form input fields. Those values will then be available to the Struts 2 action class.

We then create a proxy of the createaccount action. This action is defined in struts.xml as follows.

struts.xml
<action name="createaccount" class="edu.ku.it.si.struts2_junit_example.action.AccountAction">
	<result>/thankyou.jsp</result>
	<result name="input">/createaccount.jsp</result>
</action>

When we run this test, the proxy of the createaccount action will be executed which will cause the Struts 2 interceptors to fire (so the request scope values will be assigned to the correct Action class instance fields) and then the validate method will be executed.

The two test methods above are used to test the action's validate method when the username doesn't meet the business requirements (too few characters) and when the username does meet the business requirements.

Note in the second test method where we have the statement:

String result = proxy.execute();

This statement stores the result returned by the Action class (e.g. "success") which we can then use in an assert statement to test if the result is what it should be.

assertEquals("Result returned form executing the action was not success but it should have been.", "success", result);

Testing a Struts action against a custom Struts configuration file

Override getConfigPath method to return a comma separated list of paths to a configuration file.

Specify Struts Configuration File Location Example
    @Override
    protected String getConfigPath() {
        return "struts-test.xml";
    }

Testing A Struts Action When Using Spring

If your Struts application is using Spring to manage class relationships and you want test your Struts action class with the Spring container, then have your test class extend StrutsSpringTestCase instead of StrutsTestCase.

The StrutsSpringTestCase class expects your Spring configuration file to be loaded from classpath:applicationContext.xml (configuration file named applicationContext.xml and in the root of the class path). If your Spring configuration file has a different name or location, in your test class override method:

protected java.lang.String getContextLocations()

For example:

Specify Spring Configuration File Location Example

@Override
public String getContextLocations() {
		
  return "edu/ku/it/si/tutorial/action/TestAccountAction-context.xml";

}

  • No labels

3 Comments

  1. Anonymous

    I am using the code as an example but my test case persists the data in the database and does not rollback after its execution

  2. Anonymous

    When I execute multi aciton in the same test method, only the first aciton have the right result, but ohters are all wrong.

    How to run multi action in a test method?

    1. What you mean by multiple actions in one test method? Could you post some code sample? And ask your question via "Struts Users Mailing List" user@struts.apache.org ?