Quick Start *Classes to Use* - BaseStrutsTestCaseSpring - StrutsContextLoader
*Example Usage* - BusinessEntityControllerTest *Blog Post* - struts2-testing.txt -D
Struts2 Unit Testing http://itefforts.blogspot.com/2007/08/struts2-spring-junit.html http://depressedprogrammer.wordpress.com/2007/06/18/unit-testing-struts-2-actions-spring-junit/ http://www.appfuse.org If you are going to work with Struts2, and you haven't been under an engineering rock over the past 5 years, you are going to want to unit test your actions. Unit testing in Struts2 comes in several flavors, and I will give you a tour of resources available to you as well a recommendation for what works for me. Most developers using Struts2 are using Spring to wire their actions to various Services. We will assume that is true for you and ignore simple unit testing of an Action with no Services or using an alternative like Guice to inject dependent services. There are a few things we are looking for when we unit test: 1. We want our tests to auto wire services like they will "in the wild" 2. We don't want our calls to Services to change the state of the underlying data such that unit tests start depending on each other 3. We want to be able to test our Struts actions in a few different configurations: * Test actions with the interceptor stack * Test action methods in isolation * Test Result views (JWebUnit) - a different post all together. Testing Fixtures When you are testing you will likely want to have some pre-set data "fixtures" that your action unit tests can use. For example, you want a record in the database with the id of 1, so you can test your action.get() method with the parameter id=1. I use maven as my build tool and the db-unit plugin to setup my database with the default test fixture data. The best example of this at work is in the Appfuse framework (http://www.appfuse.org) or you can take a look at the plugin itself (http://mojo.codehaus.org/dbunit-maven-plugin/). Appfuse (Matt Raible) http://www.appfuse.org The unit testing model in Appfuse for Struts2 action focuses on unit testing the action methods in isolation of the surrounding Struts2 container environment. Actions are created and then wired to their services via Spring, parameters are then set using setters on the Action (mimicking the Parameters interceptor). Then the test will call the action methods directly, and then inspect the action using the action's getters. This method of testing works well. It is simple and easy to understand. It extends from a mouthful of a Spring JUnit utility class, AbstractTransactionalDataSourceSpringContextTests, that automatically database transactions triggered from action methods. This is important so your test fixtures are stable for every test. http://fisheye4.atlassian.com/browse/appfuse/trunk/web/struts/src/main/java/org/appfuse/webapp/action/BaseActionTestCase.java Depressed Programmer - http://depressedprogrammer.wordpress.com/2007/06/18/unit-testing-struts-2-actions-spring-junit/ My favorite name for a blog, this was the first base unit test I saw that allowed you to do the type of tests from Appfuse, or also run your actions with the full stack of interceptors. The bonus to this method is that you can test your Struts configuration and the interaction of your actions with interceptors based on the request parameters you expect to be sent. It is definitely more complicated, but it gives you some flexibility. You can test your action with mock Request parameters and the interceptor stack, or you can test the action methods directly, like Appfuse. The bad news about this test case is that it is complicated to setup your request parameters and its Struts initialization is a bit dated. It also does not provide the auto-rollback feature the Appfuse test does. The good news is that I have adapted these two testing models to create a mix of the two that I have used successfully for a while. *BaseStrutsTestCaseSpring* This base class uses Junit 4 annotations, Spring 2 testing context annotations and non-deprecated methods for initializing Struts for tests. It comes with a custom StrutsContextLoader class to fire up a WebApplicationContext from the file locations in the @ContextConfiguration annotation. You can setup your request by using the protected MockHttpServletRequest request member variable which is used when setting up the Struts2 environment. Similar to Appfuse it uses a Spring test utility, AbstractTransactionalJUnit4SpringContextTests, to automatically rollback database transactions. One thing I needed to get used to is using the Assert.assertXXX() static methods rather than just using assertXXX(). Since this is a Spring test context setup you can inject MockServices when you don't want the underlying service code to execute. I have also injected Resources so I can do things like test an attachment system from the classpath during unit tests and from the filesystem in production. I use Spring Security and so in my Struts2 actions they call out to get the "currentUser". I inject a mock SecurityManager that gives Struts2 the User they are looking for and everyone is happy! The basic setup is: * Extend the base class * Create a test method with an @Test annotation * setup your request by calling methods like request.setParameter("id","1"); * call createAction with the namespace and action name and get back an instance of your Action object you can manipulate * Do anything else to the action you want before the interceptors and action method run * execute proxy.execute() and capture the Struts result as a String (proxy is another protected member variable setup in createAction()) * Inspect your result string and action getters with Assert calls to test how it behaved. If you really want something not to rollback, you can add a @Rollback(false) annotation. I cannot remember the occasion but there have been times as I was developing tests that I turned off Rollback to see the records that got created. More likely you need some unit tests at the service level if you looking at things like that, but I am assuming I was being lazy. If you really don't care about setting Request parameters or the interceptor stack, and want to test like in Appfuse, you can get your action back and just use the action.setters, call the action.method() and then use the action.getters to check its state after. *StrutsContextLoader* This is there to setup the ServletContext to locate the webroot. If you are using Maven2, you should have no problems. If not you may have to edit the path String.... This also takes the Spring configuration files and sets them up for the WebApplicationContext. Struts Junit Plugin This includes the StrutsTestCase base class that extends XWorkTestCase. This is of course the "native" struts testing class, but I found it to be difficult to use unless you have some rather intimate knowledge of some of the more abstract Struts2 parts like ValueStack or ConfigurationManager. I never really saw a clear pattern for its use in the Struts2 code base. In fact, I see a lot of JWebUnit testing which I really only use for integration or view (JSP) testing. I am sure that the StrutsTestCase class can be updated to include the features I have described in the previous setups, and perhaps it will. But until then I would reccommend using my hybrid base TestCase. JWebUnit There is nothing special about JWebUnit for testing struts. You have to start your application up in your servlet container and then point your JWebUnit tests to the webapp. This is nice for integration testing, but its not something you run all the time. These tests are something in the "I should do those but..." category. I find my JSP/Freemarker templates are very simple and I don't make many mistakes. When I do they are very obvious so the unit tests don't help me. That said, I think they add another dimension of coverage and maintainability for your application 6 months from now, when you are deploying some patch.
BusinessEntityControllerTest.java
Description: Binary data
BaseStrutsTestCaseSpring.java
Description: Binary data
StrutsContextLoader.java
Description: Binary data
On May 15, 2009, at 2:49 PM, DUSTIN PEARCE wrote:
I can help you. When I get home tonight can send you some base test classes that will do what you want.On May 15, 2009, at 2:01 PM, wkbutler <kent.but...@gmail.com> wrote:Right, we're using Struts2. I'll investigate further, it would be nice to have the option. I'll post back if I find something useful. Thanks Matt -mraible wrote:I'm guessing you're using Struts 2? If so, this won't work because in anormal (web.xml) environment, the filters handle wiring up the dependencies.Hopefully setting the dependencies manually isn't too much of a pain. Ifitis, I'd suggest talking to the Struts 2 developers and see if there's awayto enable autowiring (or the struts2-spring-plugin) during unit testing.MattOn Fri, May 15, 2009 at 2:36 PM, wkbutler <kent.but...@gmail.com> wrote:Thanks dusty. Yes, you are correct -- test/resources contains a couple Spring configs that came default with AF2 (thanks Matt & group!) and Idon't believe I have changed them at all.Sorry, I should have said - I'm testing our Actions, and the beans aredeclared in standard beans xml files. I verified that theBaseActionTestCase is pulling in all of our expected appContexts, andindeed it is setting AUTOWIRE_BY_NAME explicitly. Hmmmmm...... Here's an example action bean, FWIW:<bean id="addressAction" class="com.e3.webapp.action.AddressAction"scope="prototype"/> This bean should be picking up an 'addressManager' and a'localSecurityContext' reference during testing, but it's not. Both collaborators are defined as beans, and the names line up. The sameconfig files work when executing jetty:run.I have not tried used annotations for testing, BTW - ours is still an oldschool configuration.I don't see any bit of the Spring configs under test/resources that lookat all relevant, either. It's all specific to User management and datasource configuration. Thanks again - dusty wrote:Hey kent,Autowiring should work for your unit tests. You likely have a spring configuration file in your test/resources directory. If you are using Spring annotations, you can make sure that they are configured to bescanned in your test applicationContext.xml.There is a base test class, BaseDaoTestCase that gets things setup andfires up Spring for your tests. If you changed your Spring configfile names or locations you need to update this test class since it has the Spring config file locations as a static array of Strings if Iremember correctly.Other than that what are you trying to wire? What are you trying totest, DAO, Manager or Controller? -D On May 14, 2009, at 8:58 PM, wkbutler wrote:Hi all -We're using Spring bean autowiring during the regular execution ofour app. I believe this is a feature of the ContextLoaderListener which is specified in the web.xml. That works great.In unit testing however, autowiring is not automatically enabled. OurSpring contexts are getting picked up from the classpath however, same as always. Does anyone know how I can enable autowiring for unit testing? Seems like a configuration to the context currently being used by the unit tester, but to be honest I have not yet figured out how the unit testing mojo is configured. Thanks for any pointers. Kent -- View this message in context:http://www.nabble.com/Spring-Autowiring-during-Unit-testing-tp23553006s2369p23553006.htmlSent from the AppFuse - User mailing list archive at Nabble.com. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@appfuse.dev.java.net For additional commands, e-mail: users-h...@appfuse.dev.java.net--------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@appfuse.dev.java.net For additional commands, e-mail: users-h...@appfuse.dev.java.net-- View this message in context: http://www.nabble.com/Spring-Autowiring-during-Unit-testing-tp23553006s2369p23566907.html Sent from the AppFuse - User mailing list archive at Nabble.com. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@appfuse.dev.java.net For additional commands, e-mail: users-h...@appfuse.dev.java.net-- View this message in context: http://www.nabble.com/Spring-Autowiring-during-Unit-testing-tp23553006s2369p23567226.html Sent from the AppFuse - User mailing list archive at Nabble.com. --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@appfuse.dev.java.net For additional commands, e-mail: users-h...@appfuse.dev.java.net--------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@appfuse.dev.java.net For additional commands, e-mail: users-h...@appfuse.dev.java.net
--------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@appfuse.dev.java.net For additional commands, e-mail: users-h...@appfuse.dev.java.net