How to Test Struts 2 Actions Without a Container
I recently worked on a project that used Struts 2.1 and the Spring framework integration plug-in. There are sporadic examples of how to test Struts actions in this context but none of them seemed to be up-to-date or they required you to start a servlet container to run the tests. None of the examples I found also showed you how to leverage Spring's transactional JUnit helper classes which enable you to run tests in a transaction and automatically rollback after each test. This is a huge benefit if you're working with a project where lots of test data is needed.
Since none of the existing examples seemed to address my needs, I put together a solution using a combination of mock objects and Spring's test helper classes.
Here's what you need:
- Java 5 or above
- Struts 22.214.171.124 (including the junit and spring integration plug-ins)
- Spring Framework 2.5.6 (including spring)
- JUnit 4.4
The versions outlined above are the ones I used so I know they work. You may be able to use slightly different versions.
The approach I use here will have the following benefits:
- Little to no manual setup and configuration required for tests.
- Since the tests are transactional, there's no need to manually clean up test data. Each time the tests are run, the database returns to the state it was in before running a test.
- Easy overrides. Using a combination of annotations and helper methods provided by JUnit, Struts and Spring superclasses, you can easily modify the default behavior of tests.
Let's get started with some code.
I started with a base class called StrutsSpringTransactionalTests which extends the StrutsSpringTestCase. The StrutsSpringTestCase is bundled with the struts2-junit-plugin.jar and provides functionality for adding the Spring context to the servlet context (normally achieved via the web descriptor).
Wiring in Spring Configuration and Setting DataSource
From here, extend the StrutsSpringTransactionalTests class:
You can optionally combine the above two classes. I separated them in order to reuse StrutsSpringTransactionalTests across different Struts applications.
Struts Action Test Implementation
Finally, here's an example of a test class which leverages AppTransactionalStrutsTestCase:
When the above test runs, any database operations are automagically rolled back.