Mock Object Testing Using JUnit, StrutsTestCase, and Ant


This section is based on the strutsJUNIT.zip file that's included on the CD-ROM that accompanies this book. Other sections of this chapter use different archives.

The first test you create is a simple mock object test for the Hello World application.

How do you know where to begin and what to test? The easiest way is to look at the code you need to test and just start there. To begin, here's a snippet from the HelloAction.java file:

 // If this is first time, go straight to page         String action = request.getParameter("action");         if (action == null) {             return (mapping.findForward("SayHello"));         } 

This code snippet is near the beginning of the execute method in the HelloAction class. This code implements the logic that if no request parameter with the name action exists, the Action class should forward processing to the ActionForward defined in the struts-config.xml file as SayHello .

Given that this is a piece of conditional logic that requires processing to continue one of two different ways depending on some condition, this is an ideal candidate for testing. Listing 20.2 is the test case to test it.

Listing 20.2 TestHelloAction.java ”A Test Case for Testing the Hello World Struts Application
 package ch20.hello.mocktest; import servletunit.struts.MockStrutsTestCase; public class TestHelloAction extends MockStrutsTestCase {     public TestHelloAction(String testName) { super(testName); }     public void testNoParameters() {        setRequestPathInfo("/HelloWorld");        actionPerform();        verifyForward("SayHello");     } } 

The following are some general observations on this class:

  • It's very short. Considering the overall complexity of what's going on, the developers of the StrutsTestCase testing framework have done an excellent job of simplifying the development of test cases for Struts applications.

  • The test case simply sets a request path ( /HelloWorld ) that the mock objects should test, and then runs the core Struts Action servlet. This invokes Struts, which chooses the appropriate Action class based on the entries in your struts-config.xml file.

  • Setting up request parameters is done using the addRequestParameter ( name , value ) method. As you can see from the listing, no request parameters were set up prior to invoking actionPerform . This tells the mock objects to test processing when no request parameters are present. (Other tests are done later in the chapter that demonstrate how to set request parameters correctly.)

  • Invoking the actionPerform method causes form bean processing to be performed exactly as it would be if you actually were running Struts. The form bean is populated the same way and the validate method is called if your struts-config.xml indicates it should be.

  • All processing after the actionPerform statement is for checking results. This is how you test whether the test ran correctly. This test case tests to make sure that the Action class sends processing to the SayHello ActionForward .

In English, this test case says, "Test whichever Action class is invoked when the path /HelloWorld.do is requested . Assume that no request parameters are set. Make sure that after processing is complete, the Action class forwards to the SayHello ActionForward ."

Configuring Your System to Run the Mock Object Tests

A number of different configuration steps are required for this testing to work correctly. Ant, Cactus, JUnit, and StrutsTestCase must all be installed and/or have their configurations set.

Given the number of packages involved ”not to mention Struts and the other packages you've likely already installed ”there's ample room for configuration problems here. In fact, we found this to be one of the more challenging chapters in terms of overall configuration.

To address this, we've included working versions of the sample applications in this chapter on the companion CD-ROM for this book. You might be able to get the applications working on your own just by getting the latest versions of all the packages in use here and configuring them according to their instructions. However, if you have trouble, we advise you to use the versions that we supply. They've all been tested by at least two different people to make sure they work.

Configuring Ant for the Mock Object Testing

Your Ant installation must be updated before these tests can be run. That's because the JUnit code is not part of the standard Ant installation.

The easiest approach to upgrading your Ant installation is to use the version that comes on the companion CD-ROM to this book. It's a release of Ant that was put together by the Jakarta Cactus project team. It's actually just a standard release of version 1.5 of Ant, but it comes with all the libraries installed in the correct versions to enable you to run JUnit, Cactus, and so on with no problems.

This approach also has the impact of upgrading your Ant installation to be able to run the in-container testing that comes later in the chapter.

If you choose another route to upgrading, we recommend you refer to the documentation for Ant, JUnit, Cactus, and StrutsTestCase. (As much as we'd like to provide you configuration instructions for your exact environment, it's really impossible .) Generally, the steps include installing the Ant optional task library along with the supporting library files required by the JUnit and Cactus code. The specific library files you need might change depending on the versions of each of these applications you're using.

Adding the Required Libraries to Your Struts Application

Because you'll be adding test cases to the Hello World Struts application, you must add several JAR files to the application to support them. Specifically, these are

  • strutstest.jar The StrutsTestCase library file included on the companion CD-ROM.

  • junit-3.7.jar This is the version of JUnit that StrutsTestCase extends. It's also included on the CD-ROM.

  • servlet.jar Required because StrutsTestCase generates mock objects that impersonate a servlet container. This file comes with Tomcat and is located in the /common/lib subdirectory under your Tomcat home directory. This library must be copied to the ${lib.home} directory to make it available at compile time.

The files must be copied to the directory identified by Ant as the ${lib.home} for the build process. This ensures that the build process puts them into the .war file for the Web app.

Adding the Test Case to the Application and Modifying the Build File

Now that you have Ant itself configured and all the libraries in place, you're almost ready to run the tests. All you have to do is add the Java file for the test case to your source path and then modify your build.xml file to execute it.

The Java file for the test case contained the package statement:

 package ch20.hello.mocktest; 

Putting the test case Java files in a test package directly below the package containing the files being tested, as you're doing here, is a common approach. So, for this step, simply create the directory ${src.home}/ch20/hello/mocktest in your development area and copy this test case file there. When you run your build.xml file, it automatically picks it up and compiles it with the other files.

Now you need to modify the build.xml file to run the test case. To do so, edit your build.xml file and add the following target:

 <!-- ==================== "test" Target ================================== -->     <!--         This task runs all test cases. It invokes each test case individually.         The "test-all" target is tied back to the "struts-test" target which         actually runs the tests. This allows other test targets to be created         in this section while maintaining the ability to run each test target         individually. All individual test targets should be added to the         "depends" attribute of the "test-all" target to provide a single         target that runs all tests. -->   <target name="test-all" depends="struts-tests" />   <target name="struts-tests" depends="build" >       <junit printsummary="yes" >           <classpath >               <pathelement location="${object.home}"/>               <pathelement location="${build.home}"/>               <pathelement location="${build.home}/WEB-INF/classes"/>               <path refid="compile.classpath"/>           </classpath>           <formatter type="plain" />           <test name="ch20.hello.mocktest.TestHelloAction" />       </junit>   </target> 

In addition, you should add two lines to the help target in the build.xml file indicating there are now two more targets that this build file knows how to build.

You should review the Ant documentation for all the options and details of the <junit> Ant task, but here are the high points of this particular usage:

  • Two targets are defined: test-all and struts-tests . This is so there can be a top-level testing target as well as lower level targets. This enables you to run all the tests or just a single test if you need to.

  • The struts-test target depends on the build target. This ensures that all Java files are compiled and any changes to properties files or the struts-config.xml have been copied to the build directory prior to running the tests.

  • The <classpath> contains, among other elements, a reference to the ${build.home} directory, even though there are no class files directly below it. This is on the classpath so that the StrutsTestCase libraries can locate the struts-config.xml file. By default, the StrutsTestCase libraries search the classpath for a directory named WEB-INF and then look for the struts-config.xml file there (although this default behavior can be overridden).

  • The <formatter> element is used to tell JUnit how to format the output from its tests. This example uses the plain type, but there are other types as well. For example, it's common to use the xml type to generate XML-based output that can be used with an XSL stylesheet to generate custom results pages. This entails using the related <junitreport> Ant task.

  • This example shows only a single test case being run. To add additional test cases, you can either add additional <test> elements or use a <batchtest> element to specify groups of tests to run.

By default, the output for this test is saved in the file TEST-ch20.hello.mocktest.TestHelloAction.txt . This filename can be overridden using the outfile attribute of the <test> task.

Running the Mock Test Case and Viewing the Results

Now that everything is configured, it's time to actually run the test. To do so, you simply type:

  ant test-all  

You should then see output from the build file as it makes directories, compiles the code, and copies files around. The lines related to running the tests are

 struts-tests:     [junit] Running ch20.hello.mocktest.TestHelloAction     [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 2.042 sec test-all: BUILD SUCCESSFUL 

This indicates that a single test was run and that there were no errors. Output from the test is in the default output file ( TEST-ch20.hello.mocktest.TestHelloAction.txt ), which should read

[View full width]
 
[View full width]
Testsuite: ch20.hello.mocktest.TestHelloAction Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 2.042 sec ------------- Standard Error ----------------- [INFO] ServletContextSimulator - -ActionServlet: init [INFO] PropertyMessageResources - -Initializing, config='org.apache.struts.util. graphics/ccc.gif LocalStrings', returnNull=true [INFO] PropertyMessageResources - -Initializing, config='org.apache.struts.action. graphics/ccc.gif ActionResources', returnNull=true [INFO] PropertyMessageResources - -Initializing, config='ch20.hello.ApplicationResources', graphics/ccc.gif returnNull=true [INFO] RequestProcessor - -Processing a 'POST' for path '/HelloWorld' ------------- ---------------- --------------- Testcase: testNoParameters took 2.042 sec

The output indicates a successful execution of the testNoParameters test case.

Note that if the build file output indicated there were errors running the test, these errors would show up here. Virtually any errors you encounter at this point would be related to configuration, classpath issues, or having incorrect JAR file versions. If you run into problems and have trouble resolving them, please follow the instructions earlier in this chapter on configuring your system.

Testing Additional Struts Functionality in the Mock Test Case

Now that you have a working configuration and have run a test case, let's see what other options StrutsTestCase provides for testing Struts components . Listing 20.3 is TestHelloActionMultiple.java , a test case containing multiple individual test cases.

Listing 20.3 TestHelloActionMultiple.java ”A Test Case Containing Multiple Individual Test Cases
 package ch20.hello.mocktest; import servletunit.struts.MockStrutsTestCase; public class TestHelloActionMultiple extends MockStrutsTestCase {     public TestHelloActionMultiple(String testName) { super(testName); }     public void testNoParameters() {        // Basic test to illustrate functionality        setRequestPathInfo("/HelloWorld");        actionPerform();        verifyForward("SayHello");        // Test Form Bean validations        verifyActionErrors(new String[] {"ch20.hello.no.person.error"});     }     public void testBadPerson() {        // Now test Talking to the Bad Person ("Atilla the Hun")        addRequestParameter("action","getName");        addRequestParameter("person","Atilla the Hun");        setRequestPathInfo("/HelloWorld");        actionPerform();        verifyForward("SayHello");        verifyActionErrors(new String[] {"ch20.hello.dont.talk.to.atilla"});     }     public void testHappyPath() {        // Now test the "Happy Path"        addRequestParameter("action","getName");        addRequestParameter("person","Struts Kick Start Guys");        setRequestPathInfo("/HelloWorld");        actionPerform();        verifyForward("SayHello");        verifyNoActionErrors();    } } 

As you can see, these three tests perform a pretty good test of the functionality of this application. Although you should refer to the Javadoc and other documentation on StrutsTestCase for more details, the following is a high-level view of the three test cases run here:

  • testNoParameters This test case tests the condition where HelloWorld.do is called with no name or action request parameters. The response expected is that HelloAction should return the ActionForward SayHello and the form bean should create the ActionError ch20.hello.no.person.error because no name was submitted. (Note: When I first ran this test, I forgot to update the HelloForm.java file. It was still using the original ch03.hello.no.person.error ”the test case flagged this for me and I fixed the problem!)

  • testBadPerson This test case tests the condition where HelloWorld.do is called and the name request parameter equals Atilla the Hun (the person we aren't supposed to talk to!). The response expected is that HelloAction should return the ActionForward SayHello and create the ActionError ch20.hello.dont.talk.to.atilla .

  • testHappyPath This test case tests the normal processing of HelloAction when all request parameters are appropriate. The expected response is that HelloAction should return the ActionForward SayHello and no ActionError s should be created.

Now that the test case is created, you can run the test and view the results.

Running the Mock Test Case and Viewing the Results

Just as before, copy this test case to the ${src.home}/ch20/hello/mocktest directory, go to the directory where your build.xml file is, and type

  ant test-all  

Again, you should see output from the build file as it makes directories, compiles the code, and copies files around as needed. The lines related to running the tests are

 struts-tests:     [junit] Running ch20.hello.mocktest.TestHelloAction     [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 1.542 sec     [junit] Running ch20.hello.mocktest.TestHelloActionMultiple     [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 1.793 sec test-all: BUILD SUCCESSFUL 

As you can see, all three of the new test cases added in TestHelloActionMultiple.java were run and they all completed successfully. Output from the test is in the default output file ( TEST-ch20.hello.mocktest.TestHelloActionMultiple.txt ), which should read

[View full width]
 
[View full width]
Testsuite: ch20.hello.mocktest.TestHelloActionMultiple Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 2.013 sec ------------- Standard Error ----------------- [INFO] ServletContextSimulator - -ActionServlet: init [INFO] PropertyMessageResources - -Initializing, config='org.apache.struts.util. graphics/ccc.gif LocalStrings', returnNull=true [INFO] PropertyMessageResources - -Initializing, config='org.apache.struts.action. graphics/ccc.gif ActionResources', returnNull=true [INFO] PropertyMessageResources - -Initializing, config='ch20.hello.ApplicationResources', graphics/ccc.gif returnNull=true [INFO] RequestProcessor - -Processing a 'POST' for path '/HelloWorld' [INFO] ServletContextSimulator - -ActionServlet: init [INFO] PropertyMessageResources - -Initializing, config='org.apache.struts.action. graphics/ccc.gif ActionResources', returnNull=true [INFO] PropertyMessageResources - -Initializing, config='ch20.hello.ApplicationResources', graphics/ccc.gif returnNull=true [INFO] RequestProcessor - -Processing a 'POST' for path '/HelloWorld' [INFO] ServletContextSimulator - -ActionServlet: init [INFO] PropertyMessageResources - -Initializing, config='org.apache.struts.action. graphics/ccc.gif ActionResources', returnNull=true [INFO] PropertyMessageResources - -Initializing, config='ch20.hello.ApplicationResources', graphics/ccc.gif returnNull=true [INFO] RequestProcessor - -Processing a 'POST' for path '/HelloWorld' ------------- ---------------- --------------- Testcase: testNoParameters took 1.262 sec Testcase: testBadPerson took 0.54 sec Testcase: testHappyPath took 0.211 sec

Any errors would've been displayed here as well. Again, if you're having configuration issues, please refer to the earlier section of this chapter on system configuration.



Struts Kick Start
Struts Kick Start
ISBN: 0672324725
EAN: 2147483647
Year: 2002
Pages: 177

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