vmassol 01/05/12 04:56:31
Modified: cactus/docs/framework/xdocs doc-book.xml index.xml
site-book.xml
Added: cactus/docs/framework/xdocs mockobjects.xml
Log:
added a Mock Objects vs In-Container web page that explains differences in strategy
and pros and cons of each
Revision Changes Path
1.9 +5 -1 jakarta-commons/cactus/docs/framework/xdocs/doc-book.xml
Index: doc-book.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/cactus/docs/framework/xdocs/doc-book.xml,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- doc-book.xml 2001/05/02 17:00:26 1.8
+++ doc-book.xml 2001/05/12 11:56:30 1.9
@@ -25,8 +25,12 @@
<menu-item label="Downloads" source="downloads.xml"/>
</menu>
- <menu label="User Guides">
+ <menu label="Design">
<menu-item label="Architecture" source="architecture.xml"/>
+ <menu-item label="Mock vs Container" source="mockobjects.xml"/>
+ </menu>
+
+ <menu label="User Guides">
<menu-item label="Installation" source="installation.xml"/>
<menu-item label="Installing Ant" source="installation_ant.xml"/>
<menu-item label="Installing Sample" source="installation_sample.xml"/>
1.8 +11 -0 jakarta-commons/cactus/docs/framework/xdocs/index.xml
Index: index.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/cactus/docs/framework/xdocs/index.xml,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- index.xml 2001/05/02 15:58:45 1.7
+++ index.xml 2001/05/12 11:56:30 1.8
@@ -37,6 +37,17 @@
<table>
<tr>
<td>
+ 12/05/2001
+ </td>
+ <td>
+ New page on
+ <link href="mockobjects.html">Mock Objects vs In-container</link>
+ unit testing strategies. Explains principles and details pros and
+ cons of each.
+ </td>
+ </tr>
+ <tr>
+ <td>
02/05/2001
</td>
<td>
1.8 +5 -1 jakarta-commons/cactus/docs/framework/xdocs/site-book.xml
Index: site-book.xml
===================================================================
RCS file: /home/cvs/jakarta-commons/cactus/docs/framework/xdocs/site-book.xml,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- site-book.xml 2001/04/29 19:05:59 1.7
+++ site-book.xml 2001/05/12 11:56:30 1.8
@@ -25,8 +25,12 @@
<menu-item label="Downloads" source="downloads.xml"/>
</menu>
- <menu label="User Guides">
+ <menu label="Design">
<menu-item label="Architecture" source="architecture.xml"/>
+ <menu-item label="Mock vs Container" source="mockobjects.xml"/>
+ </menu>
+
+ <menu label="User Guides">
<menu-item label="Installation" source="installation.xml"/>
<menu-item label="Installing Ant" source="installation_ant.xml"/>
<menu-item label="Installing Sample" source="installation_sample.xml"/>
1.1 jakarta-commons/cactus/docs/framework/xdocs/mockobjects.xml
Index: mockobjects.xml
===================================================================
<?xml version="1.0"?>
<!--
<!DOCTYPE document SYSTEM "./dtd/document-v10.dtd">
-->
<document>
<header>
<title>Mock Objects vs In-Container testing</title>
<authors>
<person name="Vincent Massol" email="[EMAIL PROTECTED]"/>
</authors>
</header>
<body>
<s1 title="Mock Objects vs In-Container testing">
<p>
Using Mock Objects is a way to unit test java classes in general, that
is also applicable to unit test server side code like Servlets,
Filters, Taglibs, EJBs, ... See the original article
<link href="http://www.sidewize.com/company/mockobjects.pdf">
"Endo-Testing : Unit Testing with Mock Objects"</link> for full details
on Mock Objects.
</p>
<p>
A method, when unit tested, may take parameters and may manipulate
objects from other classes. It is not the goal of this method unit
test to unit test these ancillary objects. Thus, the Mock objects
strategy is to fake the latter by using simulated copies instead of
the real objects. This enables to finely unit test the method with no
"noise" from the surrounding domain objects. In other words,
it enables the method being unit tested to be completely isolated from
its surrounding and thus its unit tests can concentrate on unit testing
its logic.
</p>
<p>
When applied to servlet testing, it means Mock Objects need
to be provided for simulating the servlet container. In other words
a Mock implementation of the Servlet API need to be provided (of course
only the Servlet API methods used in the classes under test need to be
mocked).
</p>
<p>
Cactus' strategy so far has been to rely on the container to provide
the implementation of the Servlet API. In that sense, Cactus and
Mock Objects are 2 different ways of writing unit test for servlet code
(and any other server side code for any other API).
</p>
<p>
In the rest of this article, we'll discuss the pros and cons of each
approach.
</p>
</s1>
<s1 title="An example">
<p>
Simple test case using Cactus :
</p>
<source><![CDATA[
[...]
MyServlet myServlet = new MyServlet();
[...]
public void beginXXX(ServletTestRequest theRequest)
{
theRequest.addParameter("param1", "value1");
theRequest.addParameter("param2", "value2");
}
public void testXXX()
{
myServlet.init(config);
myServlet.myMethod(request, response);
assertEquals("some value", session.getAttribute("some_name_set_in_mymethod"));
}
public void endXXX()
{
String result = AssertUtils.getResponseAsString(theConnection);
assertEquals("<html><head/><body>A GET request</body></html>", result);
}
]]></source>
<p>
Simple test case using Mock Objects :
</p>
<source><![CDATA[
[...]
MockHttpServletRequest myMockHttpRequest = new MockHttpServletRequest();
MockHttpServletResponse myMockHttpResponse = new MockHttpServletResponse();
MockServletConfig myMockServletConfig = new MockServletConfig();
MyServlet myServlet = new MyServlet();
[...]
public void testXXX()
{
myMockHttpRequest.setupAddParameter("param1", "value1");
myMockHttpRequest.setupAddParameter("param2", "value2");
myMockHttpRequest.setExpectedAttribute("some_name_set_in_mymethod", "some
value");
myMockHttpResponse.setExpectedOutput("<html><head/><body>A GET
request</body></html>");
myServlet.init(myMockServletConfig);
myServlet.myMethod(myMockHttpRequest, myMockHttpResponse);
myMockHttpRequest.verify();
myMockHttpResponse.verify();
}
]]></source>
</s1>
<s1 title="Pros and Cons">
<p>
Comparison of pros and cons of Mock Objects (MO)
versus In-Container/Cactus (IC) but also of MO in general
versus no MO.
</p>
<note>
This table is not meant to be comprehensive in
term of benefits/inconvenients of using MO. It is more focused on
pros and cons of MO when used for unit testing server side code
(Servlets for example)
</note>
<table>
<tr>
<th>
Issue
</th>
<th>
MO
</th>
<th>
IC
</th>
</tr>
<tr>
<td>
MO let us test methods even before the domain objects are ready,
i.e. before the implementation are ready. Or before a choice of
implementation has been made. Thus, for example, it is possible to
write servlet code before choosing a container. This is in
accordance with XP that says : "not commit to infrastructure choice
before you have to" and "write unit test first".
</td>
<td>
+
</td>
<td/>
</tr>
<tr>
<td>
MO is comprehensive/universal. It adapts to all kind of unit testing :
Servlet unit testing, JDBC unit testing, Struts unit testing, ...
Cactus only addresses server-side testing, meaning that if in your
Servlet code you have JDBC connections and you want to unit test
the methods that does database access you still need to have a
MO-like strategy, thus you need to understand and learn 2 strategies.
</td>
<td>
+
</td>
<td/>
</tr>
<tr>
<td>
Running MO tests is very fast as it does not rely on having to run
a container. Thus tests can be run very often. IC testing need to
start the container, run the tests, stop the container. However,
this can be alleviated by using Ant and by using a reloadable
container (the majority of servlet engines do dynamic reloading).
</td>
<td>
+
</td>
<td/>
</tr>
<tr>
<td>
It is possible to write generic MO suite for a given API set. It
fits very well with the Jakarta frameworks in the sense that it is
possible to write an MO suite for the Servlet API, but also an MO
suite for Struts, an MO suite for Velocity, ... There can 3 levels
in an MO unit testing framework : the core level providing basic
core functionality, some standard API level libraries (like a MO
library for the Servlet API, for Taglibs, ...) and some
application API level libraries (like a MO library for Struts, ...).
Whereas, if we want to ease unit testing of Struts Actions
(for example) using Cactus, we still need to make available a
MO suite for Struts. The question then is : As this Struts MO suite
does not have the same goal as Cactus, where do we host it ? In
Cactus, in Struts, somwhere else ?
</td>
<td>
+
</td>
<td/>
</tr>
<tr>
<td>
Using MO force the developer to refactor his code. As an example he
needs to ensure that interfaces are provided for domain objects so
that a Mock implementation can be implemented. There are other
more subtle refactoring involved like smart handler passing instead
of more fine grained data (thus leading to better encapsulation). It
follows XP refactoring rules.
</td>
<td>
+
</td>
<td/>
</tr>
<tr>
<td>
Using MO, it is not sure the classes will run correctly in the
chosen servlet engine. On the other hand, IC tests ensures that
all code will run perfectly well in container.
</td>
<td/>
<td>
+
</td>
</tr>
<tr>
<td>
MO does not include a build/deployment methodology whereas Cactus
does. This could certainly be included in a Cactus-like framework
based on MO.
</td>
<td/>
<td>
+
</td>
</tr>
<tr>
<td>
MO tests tend to be very fine-grained. Thus, there is no assurance
that object interactions will work properly and thus functional
tests are a must. However, this is probably simply a question of
practice as the granularity of MO can vary depending on the test
case needs.
It means that it is possible to implement a very fine grain test
case and then another test case where we mock less domain objects
and use more real objects instead.
</td>
<td>
+/-
</td>
<td/>
</tr>
<tr>
<td>
Using generic MO libraries is against some of MO practices. For
example, a good practice is to factorize domain object asserts in
the mock implementation instead of in the test case (this is called
Refactored Assertions). This is
possible only if the Mock implementation is project specific. So,
for some parts, MO does not fit that well with the idea of generic
libraries. A middle ground could probably be found.
</td>
<td>
-
</td>
<td/>
</tr>
<tr>
<td>
Using MO is not simple. It needs some discipline and some
experience. Same as for unit tesing using JUnit, there are some
methodologies to follow. Some are :
<ul>
<li>
In order not to be weighted down by having to implement myriad
of MO, these implementation need to be the simplest possible,
i.e. do nothing method at first and then slowly over time,
during refactoring, implement what is needed at the current
time.
</li>
<li>
One must resist the temptation to reimplement the domain logic
in the MO. There must be almost no logic at all in MO.
</li>
<li>
MO must not make calls to other MOs ... When it happens, there
is a need for MO refactoring !
</li>
</ul>
</td>
<td>
-
</td>
<td/>
</tr>
<tr>
<td>
In some cases MO mandates creating API that are no normally
needed, like having to offer a
<code>init(MockObject)</code> method in a Servlet in order to
initialize a mock version of an internally used domain object. Also
the code may become more complex (even if more flexible) because
of the need for testing and not because of business requirements :
for example, one might need to introduce a factory when it was not
needed simply to be able to provide MO objects from the factory.
</td>
<td>
-
</td>
<td/>
</tr>
<tr>
<td>
It may not be possible to create generic MO libraries that fit all
the needs. For example a generic JDBC MO library may not be possible
and might need database specific MO libraries. Also the cost and
complexity of a generic MO library may be higher than just
reimplementing from scratch just the needed mocked parts.
</td>
<td>
-
</td>
<td/>
</tr>
<tr>
<td>
MO does not always work well. For example the API being mocked need
to offer the correct interfaces and means to override/set internal
objects. IC has the same problem but if a test service can be
included from within the container (i.e. be part of the API SPI,
like the container API part from Servlet API) it would solve this
problem (see <link href="goals.html">Cactus goals</link>).
</td>
<td>
-
</td>
<td/>
</tr>
</table>
</s1>
<s1 title="Conclusion">
<p>
Mock Objects are a very interesting way of doing unit testing which
could bridge the gap between standard java class unit testing and
server-side testing of container components. I would say the biggest
difference between the way Cactus currently works and Mock Objects is
that Cactus tests tend to be more coarse-grained and they also ensure
that developed code will run in the container. On the other hand, Mock
Objects are more satisfactory intellectually because they are not
limited to servlet unit testing but cover the whole spectrum of code.
</p>
<p>
I would very much like to have your feedback on Mock Objects versus
In-Container/Cactus testing. Please post your feedback on the
<link href="mailto:[EMAIL PROTECTED]">jakarta-commons
</link> mailing list and prefix your
subject with "<code>[cactus]</code>" (To subscribe, send an empty
mail to <link href="mailto:[EMAIL PROTECTED]">
[EMAIL PROTECTED]</link>).
</p>
<p>
I would also like to point out that I am
not opposed to changing Cactus strategy (from In-Container to Mock
Objects) in a future version (like a 2.0). In that case, Cactus could
for example provide the 3 levels of frameworks mentionned above : core
library + standard API libraries (Servlets, Taglibs, ...) + Jakarta
oriented API libraries (Struts, Turbine, ...)
</p>
<p>
Thanks a lot.
</p>
</s1>
<s1 title="Resources">
<p>
Some links :
</p>
<p>
<ul>
<li>
<link href="http://www.sidewize.com/company/mockobjects.pdf">
"Endo-Testing : Unit Testing with Mock Objects"</link>
</li>
<li>
<link href="http://sourceforge.net/projects/mockobjects">Mock Object
project</link> on SourceForge
</li>
<li>
<link href="http://www.xpdeveloper.com">xpdeveloper.com</link> web
site and it's Extreme Tuesday Club (Xtc) ...
</li>
</ul>
</p>
</s1>
</body>
</document>