|
Last update : June 18 2001
Home
Jakarta Commons
About
News
Features
Goals
Changes
Todo
Contributors
Contributing
License
Downloads
Downloads
Design
Architecture
Mock vs Container
User Guides
Installation
Installing Ant
Installing Sample
Configuration
Writing Test Case
Servlet Sample
Ant integration
Servlet Engines
API Reference
Support
CVS
Bug database
Mailing lists
FAQ
Misc.
Resources
|
Assumptions that lead to the current Cactus design |
Here are some assumptions that I have made for the design of Cactus :
Assumptions
|
Assumption 1
|
The tests need to run on the server side. Indeed in a component model,
the components have a closed relationship with their container : they
benefit from the container's services, ... and thus they cannot
easily be run outside the container. Simulating a container is too
much work and leads to building a complete new container if all
features need to be supported.
|
Assumption 2
|
We need to be able to launch the tests that are located on the
server side. The solution is to use a proxy class that is located on
the server side. There are 2 possible implementations : (1) use a
servlet which starts the tests or (2) use an EJB. I have chosen a
servlet because it is the simplest solution and not all servlet
engine also support EJBs.
|
Assumption 3
|
We need to call this servlet. Again 2 solutions : (1) open a browser
and call the servlet URL or (2) write some java code that uses the
URLConnection class to automatically call the servlet.
This is what I call the client side part of Cactus. Of course the
best solution is (2) for the following reasons :
- The tests can be automated, i.e. it is possible to do automatic
regression tests. See the
eXtreme Programming
philosophy for better understanding this. The rationale is :
everytime you modify some piece of code, you run all the tests
again to make sure everything is still working.
- It is possible to verify the results returned by the Servlet :
cookies, headers, ... By calling directly the Servlet URL in a
browser, it is not possible to do so.
|
Assumption 4
|
In order to formalize test suites and have a sexy GUI interface there
were 2 solutions : (1) make my own framework and GUI or (2) use a
well-known, everywhere used framework. Of course, I have chosen this
second solution : all the tests are started using JUnit.
|
|
How it works |

The process is as follows for each XXX test method of your
TestYYY test class :
-
JUnit calls your the
TestYYY.runTest() method (inherited
from ServletTestCase ). This later looks for a
beginXXX(ServletTestRequest) method. If one is found,
it executes it. This is executed on the client side (i.e. not in a
server engine). The ServletTestRequest
parameter passed to the beginXXX() method is used
to set the HTTP headers, the HTTP parameters, ... that will be
sent in step 2 to the Redirector proxy.
-
The
TestYYY.runTest() method then opens an HTTP
connection to the Redirector proxy. All the parameters set up
in the beginXXX() method are put in the HTTP request
(HTTP headers, HTTP parameters, ...)
-
The Redirector proxy acts as a proxy for your
TestYYY
test class, but on the server side. It means that TestYYY
is instantiated twice : once on the client side and once on the
server side. The client side instance is used for executing the
beginXXX() and endXXX() methods (see
steps 1 and 8) and the server side instance is used for executing
the testXXX() methods (see step 4). The Redirector
proxy does the following :
-
creates an instance of
TestYYY using reflection. It
sets by reflection the Cactus implicit objects (see the section
below on Servlet Redriector Proxy and JSP Redirector Proxy for a
list of available objects).
-
creates instances of Cactus wrappers for some server objects
(
HttpServletRequest , ServletConfig ,
ServletContext , ...). This is to be able to
to override some methods in order to return simulated values.
For example, the Cactus framework can simulate an URI (i.e.
act as if this URI was called instead of the Redirector proxy
URI). Thus, the getServerName() , getServerPort() ,
getRequestURI() , ... methods return values based
on the simulated URI (if there is any defined by the user).
-
creates an HTTP Session if the user has expressed the wish
(using the
ServletTestRequest.setAutomaticSession(boolean)
code in the beingXXX() method. By default a session
is always created) and it fills by reflection the
session implicit object.
-
The
TestYYY.setUp() , TestYYY.testXXX() and
tearDown() methods are executed (in that order). They
are called by the Redirector proxy using reflection.
-
Your
TestYYY.testXXX() method calls your server
side code, executing the test and using the JUnit asserts to assert
the result (assert() , assertEquals() ,
fail() , ...)
-
If the test fails, your
TestYYY.testXXX() methods
throws exceptions to the Redirector proxy.
-
If an exception has been raised, the Redirector proxy returns the
information about the exception (it's name, class, stack trace) back
to the client side. It will then be printed by JUnit in it's Test
Runner console.
-
If no exception occurred, the
TestYYY.runTest()
method looks for an endXXX(HttpURLConnection) method
and executes it if found. At this stage, you have the opportunity
to check returned HTTP headers, Cookies and the servlet output
stream in the endXXX() method, again using JUnit asserts
and helper utility classes provided by Cactus (see the sample
application).
Redirector Proxies |
Cactus provides 2 implementation for the Redirector Proxy :
-
A Servlet Redirector. This redirector is a servlet that
should be used for unit testing servlet methods. It provides the
following implicit objects :
request ,
response , session and config .
-
A JSP Redirector. This redirector is a JSP page that
should be used for unit testing server code that need access to
the following objects :
pageContext and
out . These objects are provided in addition to all the
objects provided by the Servlet Redirector. It can be useful for
testing simple JSP custom Tag libraries.
 |
Testing custom JSP Tag libraries is still in beta. I am still not sure
of the usefulness of this ... I think unit testing tag libraries is
much less relevant than doing functional tests, but this is an open
subject ...
|
Servlet Redirector Proxy |

The client side opens 2 HTTP connections to the Servlet redirector.
Once to execute the tests and retrieve the servlet output stream and
a second time to get the test result. This is to be able to get
the exception data (message, stack trace, ...) if the test failed.
The test results are stored in a servlet-context-wide scope variable
which is retrieved on the second HTTP connection.
|
JSP Redirector Proxy |

The client side opens 2 HTTP connections. Once to the Redirector
JSP to execute the tests and retrieve the JSP output stream and
a second time to the Servlet Redirector to get the test result.
This is to be able to get the exception data (message,
stack trace, ...) if the test failed.
The test results are stored in a servlet-context-wide scope variable
which is retrieved on the second HTTP connection.
|
|
|
|
|