Recipe13.7.Testing Your Actions in the Container


Recipe 13.7. Testing Your Actions in the Container

Problem

You want to unit test an action as it's running within your application server.

Solution

Use StrutsTestCase to create a test that can be run using the Cactus integration testing framework.

Discussion

Recipe 13.6 shows you how to test an action independently from the servlet container using StrutsTestCase (http://strutstestcase.sourceforge.net). You can use Struts-TestCase, in conjunction with the Cactus testing framework (http://jakarta.apache.org/cactus), to test Struts actions running in the servlet container. This type of testing is referred to as integration unit testing.

Integration unit testing isn't unit testing in the pure sense. Unit tests isolate the unit from outside dependencies. This makes it easier to identify the cause of errors when a test fails. However, an integrated unit test may give you a more realistic view than a non-integrated test. If you are planning on deploying your application to different application servers (or different versions of the same application server), then you'll find integration unit testing to be invaluable.

Cactus was developed to provide these types of unit tests. It was originally developed to test Enterprise JavaBeans but is equally up to the task of testing servlets, servlet filters, and JSPs. In fact, Cactus can be used to test any type of behavior that relies on a J2EE/Servlet container. However, these tests come at a cost of increased complexity and slower test performance. Using StrutsTestCase, Cactus-executed action tests are easy to write, but configuration and deployment can be complex. If you are running your unit tests frequently as part of your build process, you'll find that the build script takes more time to run. The reason Cactus tests take longer is that Cactus starts your application server every time it runs its suite of tests. A good option is to run Cactus tests periodically, such as on nightly automated builds.

Unit TestingWhere Do I Start?

If you are just starting out with unit testing, knowing where to begin can be difficult. Your manager or team lead might tell you to unit test everything, but in practical terms you need to start where you have the best chance of seeing real benefits. Here are some guidelines to help you decide what type of testing to use and when:

  • Using plain old JUnit, concentrate on unit tests for the model, first.

  • Your domain model classes hold the majority of your business logic. When something goes wrong, it's likely to be here.

  • Use the StrutsTestCase with mock objects to test your Action classes.

  • Tests using mock objects can be run faster and don't require a servlet container.

  • Use Cactus testing for those classes that rely on container-provided services.

  • For example, if you are using JNDI or testing behavior based on container-managed security, you should use Cactus.

If you're unsure about when to use a mock object test versus an in-container test, the Cactus site (http://jakarta.apache.org/cactus) includes an even-handed comparison of these two approaches.


Start by downloading and extracting the StrutsTestCase and Cactus binary distributions. Each of these packages provides separates distributions for a Servlet 2.3 (or later) container or Servlet 2.2 container. For Cactus, these versions are identified by the J2EE version as 1.3 or 1.2.

Copy the strutstest.jar file and all the JAR files from Cactus's lib directory to the WEB-INF/lib directory of your web application. Cactus uses a servlet to redirect HTTP requests to your test class. You'll need to declare this servlet in your application's web.xml file. Before the ActionServlet declaration, add this servlet declaration:

<!-- Cactus Servlet Redirector --> <servlet>     <servlet-name>         ServletRedirector     </servlet-name>     <servlet-class>         org.apache.cactus.server.ServletTestRedirector     </servlet-class> </servlet>

Before the ActionServlet servlet mapping, add this servlet mapping:

<!-- Cactus Servlet Redirector mapping --> <servlet-mapping>     <servlet-name>ServletRedirector</servlet-name>     <url-pattern>/ServletRedirector</url-pattern> </servlet-mapping>

It's time to write the test using StrutsTestCase. StrutsTestCase provides two base classes for creating tests: MockStrutsTestCase and CactusStrutsTestCase. Figure 13-8 shows how the StrutsTestCase, Cactus, and JUnit base classes relate to each other.

Figure 13-8. Relationship between JUnit, Cactus, and StrutsTestCase


You extend the MockStrutsTestCase (see Example 13-7) to create a standalone unit test for an Action. You can change a mock test into an in-container test by changing it to inherit from CactusStrutsTestCase instead of MockStrutsTestCase. Example 13-9 shows a Cactus test, identical to the excerpt in Example 13-7 of the parent class, that tests the LogonAction of the Struts MailReader example application.

Example 13-9. Cactus test for the Struts example LogonAction
package com.oreilly.strutsckbk.ch13; import org.apache.struts.webapp.example.Constants; import org.apache.struts.webapp.example.User; import servletunit.struts.CactusStrutsTestCase; public class SubmitLogonActionCactusTest extends CactusStrutsTestCase {     private static final String ACTION_PATH = "/SubmitLogon";     public SubmitLogonActionCactusTest(String testName) {         super(testName);     }     public void testValidUserLogon( ) throws Exception {         addRequestParameter("username", "user");         addRequestParameter("password", "pass");         setRequestPathInfo(ACTION_PATH);         actionPerform( );              verifyNoActionErrors( );                  User user = (User) getSession( ).getAttribute(Constants.USER_KEY);         assertNotNull("User", user);         assertEquals("Username", "user", user.getUsername( ));         verifyForward("success");     }     public void testInvalidUserLogon( ) throws Exception {         addRequestParameter("username", "junk");         addRequestParameter("password", "bond");         setRequestPathInfo(ACTION_PATH);         actionPerform( );                  verifyActionErrors(new String[] {"error.password.mismatch"});                  verifyForward("logon");     } }

The CactusStrutsTestCase provides the same verification methods available with the MockStrutsTestCase. See Recipe 13.6 for a detailed explanation of these methods.

To run the test, you have to build and deploy your application and run your application server. You can run your test using any JUnit test runner. Cactus executes your test using a client Java virtual machine (the JUnit test runner's JVM) and a server Java virtual machine (the application server's JVM).

Before running your test, you have to tell Cactus how to find your application from the client side. You will need to create a file named cactus.properties and save it on your classpath. Example 13-10 shows the cactus.properties file used in this recipe.

Example 13-10. Client-side Cactus configuration file
# Configuration file for Cactus. # Each project using Cactus need to have such a file put in the client side # CLASSPATH (Meaning the directory containgin this file should be in the  # client side CLASSPATH, not the file itself of course ... :) ) # Defines the URLs that will be used by Cactus to call it's redirectors # (Servlet and JSP). You need to specify in these URLs the webapp context # that you use for your application. cactus.contextURL = http://localhost/jsc-ch13 cactus.servletRedirectorName = ServletRedirector cactus.enableLogging=true

Like any kind of unit testing, it's pretty boring (but satisfying) when the test passes. Interesting things happen when the test fails. For a Cactus test, though it's executed from the client side, you get the failure information and stack trace from the server side. Figure 13-9 shows the results when the test was changed to send an invalid username for the testValidUserLogon( ) method.

Figure 13-9. Stack trace of a failed Cactus unit test


See Also

Lu Jian has written an interesting article, "Unit Test Your Struts Application," for ONJava. This article delves into the use of aspect-oriented programming for testing Struts applications. It can be found at http://www.onjava.com/pub/a/onjava/2004/09/22/test-struts.html.

The StrutsTestCase web site, http://strutstestcase.sourceforge.net, has an active forum for posting questions and getting answers.

Cactus can be used in many different ways and a complete treatment is beyond the scope of this recipe. In addition to Struts actions, you can use Cactus to test servlets, servlet filters, JSP pages, and custom JSP tags. Cactus works best when it's integrated in your Ant build process. You can find complete details on the Cactus web site (http://jakarta.apache.org/cactus).



    Jakarta Struts Cookbook
    Jakarta Struts Cookbook
    ISBN: 059600771X
    EAN: 2147483647
    Year: 2005
    Pages: 200

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net