ou can verify that your Web-based Java application accepts the proper inputs from the HTTP request stream and displays the proper results to the HTTP response stream by performing black box testing with HttpUnit. However, since black box testing essentially simulates a Web browser, the testing code interacts with the application code via HTTP communications, which hides the implementation details.
Unit testing, in contrast, focuses on these little details in the application code. When isolating and fixing bugs, seeing the implementation details that unit testing provides can be very useful. You can use HttpUnit for unit testing, but only when testing standard servlets. It doesn't support the popular Struts Model-View-Controller (MVC) framework. For unit testing on Struts applications, you need StrutsTestCase, a small testing library that builds on top of the JUnit testing framework. With StrutsTestCase, you can actually access the server environment and fiddle with settings and inputs at a much more granular level than with black box testing. You also can access the server environment after the response.
Mock Testing Versus In-container Testing
StrutsTestCase allows you to unit test Struts-based Web applications in two ways:
- Mock testingMock testing uses mock objects, which simulate the server API. More generally, a mock object is an object that simulates another object, usually an object in the environment you are testing under or an object within a library you are using within your application code.
- In-container testingIn-container testing uses the container API, possibly with an intermediate layer of code that adds some testing functionality. You get all of the container's abilities.
The primary downside with in-container testing is that setup is more complicated, and the efficiency of the code-test-bug fix loop is dependent on the container you use. If the servlet container requires a restart to reload modified classes and restarting the server takes a long time, then your code-test-bug fix cycle will be slower under in-container testing than under mock testing.
Another difference between the testing methods is that mock objects require a simulated object for every API function in the server environment. This can be cumbersome and tedious for the developer of the mock object library, so developers sometimes omit API functions. As a result, sometimes the mock object library may not support all of the functionality of the real server environment. For example, StrutsTestCase omits JNDI functionality. If you have JNDI bindings in the Tomcat server.xml file, you will either have to use in-container testing (which StrutsTestCase supports), or you will have to integrate a mock object with JNDI support and server.xml parsing capability into the StrutsTestCase testing library, which is not hard, but it takes some time if you are not familiar with StrutsTestCase.
Generally, adding onto the testing library you are using is a drag. After all, the testing library is supposed to handle most or all of your testing needs. The omission of API functions from the mock object library probably will hamper your ability to test when your application eventually grows complex. For example, the lack of JNDI support will probably become an issue. The traditional way to access a database is through a JNDI binding, which the container provides and the server.xml file (or other container configuration file) specifies. As your application gets more complex, you will probably gravitate towards in-container testing.
Fortunately, StrutsTestCase makes it easy to switch between mock testing and in-container testing. You choose mock testing or in-container testing by subclassing MockStrutsTestCase or CactusStrutsTestCase, respectively. You do not have to make any other changes to your code. Thus, if you want to switch from mock testing to in-container testing, simply do a textual search and replace to change all occurrences of "extends MockStrutsTestCase" to "extends CactusStrutsTestCase".