When I wrote the first part of this mini article series I left open a few things, mainly the Apache Tiles setup. In the meantime this problem also has been solved and I'm now able to give you nice little Java class, which contains everything that is necessary for Action Unit Testing with Apache Struts and Tiles.
A major problem for me was that every action that had a tiles forwarder as result handler caused a test failure once it was completed. Part of that problem is that Apache Tiles support is configured in web.xml rather than struts.xml. This is a problem because web.xml is a configuration file read by Tomcat not your application. Adding support for tiles can be done in different ways. We use a tiles listener for that and simply added
<listener>
<listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
</listener>
to our web.xml file. Nonetheless this setting is not used by the Unit Test setup as it does not consider web.xml at all. So what can we do to make it work? To answer this question I had to dive deeply into the source code of Apache Tiles, Apache Struts and even sometimes in Tomcat's code (one reason more why open source software is so great, try that with proprietary stuff). In the end I found out how to manually instantiate a tiles listener. Another point was the tiles configuration file. The one for struts (in our case struts.xml) is found autmatically, as it is in the class path, but tiles.xml simply was ignored. I got around this problem by using a file system resource loader and specified the paths to both struts.xml and tiles.xml. You have of course to adjust these pathes and the configuration file names to your environment.
Another big problem I had with that solution was that each test took around 1-2 seconds just for its setup (all the struts and tiles setup happend again and again). The tests themselves were very quick. To speed this up I moved the entire test container stuff to static storage and could improve the execution speed so by around factor 40. The whole test suite (currently consisting of ~200 tests) now executes in (handstopped) 5 seconds (a bit more than 2 used for setup). Nice!
Now to the code itself. Below is what I came up with at the end. It should compile and work nicely for you. However, I have removed anything that was specific to my environment so it might be that something is wrong. Let me know if you find odditiies or if you have a more clever idea than me to make all that work.
package ... your package name here ...; // BaseAction is the class from which all other actions are derived. You should have a similar // action that is derived from ActionSupport and implements SessionAware. // Do the setup here that is needed for every test again like log-in a user. |
package ... your package here...; import ......ActionBaseTestCase; /** * @author Mike */ public class DeleteCategoryInfoTest extends ActionBaseTestCase { private DeleteCategoryInfo action; // --------------------------------------------------------------------------------------------- @Override protected void setUp() throws Exception { super.setUp(); action = createAction(DeleteCategoryInfo.class, "", "DeleteCategoryInfo"); } public void testNoId() throws Exception { assertEquals(Action.INPUT, proxy.execute()); } public void testInvalidId() throws Exception { action.setCategoryId(-100); assertEquals(Action.INPUT, proxy.execute()); } public void testValidId() throws Exception { action.setCategoryId(6); assertEquals(Action.SUCCESS, proxy.execute()); } // --------------------------------------------------------------------------------------------- } |
proxy.execute()call will trigger the method which is set by
proxy.setMethod()or
.execute()if none is set. This is the same behavior as what you can set in the struts configuration file.