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>