Author: craigmcc
Date: Sat Oct 29 17:45:51 2005
New Revision: 329501

URL: http://svn.apache.org/viewcvs?rev=329501&view=rev
Log:
Flesh out the description of the Shale Test Framework feature, and use the
<source> markup element that Maven supports to create boxes around the
code examples.

Modified:
    struts/shale/trunk/xdocs/features.xml

Modified: struts/shale/trunk/xdocs/features.xml
URL: 
http://svn.apache.org/viewcvs/struts/shale/trunk/xdocs/features.xml?rev=329501&r1=329500&r2=329501&view=diff
==============================================================================
--- struts/shale/trunk/xdocs/features.xml (original)
+++ struts/shale/trunk/xdocs/features.xml Sat Oct 29 17:45:51 2005
@@ -342,7 +342,7 @@
         <li>Define your dialogs in an XML document, conventionally named
             <code>/WEB-INF/dialog-config.xml</code>, that conforms to the
             required DTD, which defines all the state transitions:
-            <blockquote><pre>
+<source>
 &lt;!DOCTYPE dialogs PUBLIC
   "-//Apache Software Foundation//DTD Shale Dialog Configuration 1.0//EN"
   "http://struts.apache.org/dtds/shale-dialog-config_1_0.dtd";>
@@ -360,18 +360,18 @@
   ...
 
 &lt;/dialogs>
-</pre></blockquote></li>
+</source></li>
         <li>If you have more than one dialog configuration file, or you have
             defined your only dialog configuration file as a web application
             resource with a name different than the one described above, use
             a context initiaization parameter to define a comma-delimited list
             of context-relative paths to configuration resources to be loaded:
-            <blockquote><pre>
+<source>
 &lt;context-param>
   &lt;param-name>org.apache.shale.dialog.CONFIGURATION&lt;/param-name>
   &lt;param-value>/WEB-INF/foo.xml,/WEB-INF/bar.xml&lt;/param-value>
 &lt;/context-param>
-</pre></blockquote></li>
+</source></li>
         <li>In addition to the dialog configuration resources defined by this
             context initialization parameter, a resource named
             <code>/WEB-INF/dialog-config.xml</code> will be automatically
@@ -463,7 +463,7 @@
                  </ul>
 
         <p>Here's an example:</p>
-<pre>
+<source>
 &lt;%@ taglib uri="http://struts.apache.org/shale/core"; prefix="s" %&gt;
 ...
 &lt;h:form onsubmit="validateForm(this)"&gt;
@@ -493,7 +493,7 @@
     &lt;s:validatorScript functionName="validateForm"/&gt;
 &lt;/form&gt;
 ...
-</pre>
+</source>
         <p>In the preceding example, we've attached three Commons validators 
to a single
                     JSF input component. To pass validation, the field must 
have a value that
                          starts with a number between 4 and 6 inclusive and 
that value must be a valid
@@ -587,49 +587,49 @@
         environment entry to define whether your application is running in
         debug mode or not, declared in <code>web.xml</code> like this:</p>
 
-        <blockquote><pre>
+<source>
 &lt;env-entry&gt;
   &lt;description&gt;Flag indicating whether we run in debug 
mode.&lt;/description&gt;
   &lt;env-entry-name&gt;debugMode&lt;/env-entry-name&gt;
   &lt;env-entry-value&gt;false&lt;/env-entry-value&gt;
   &lt;env-entry-type&gt;java.lang.Boolean&lt;env-entry-type&gt;
 &lt;/env-entry&gt;
-</pre></blockquote>
+</source>
 
         <p>Now, assume you have a status message that you only want to have
         displayed when debug mode is enabled.  You can bind the
         <code>rendered</code> property of the component to this environment
         entry value:</p>
 
-        <blockquote><pre>
+<source>
 &lt;h:outputText ... rendered="#{jndi.debugMode}" .../&gt;
-</pre></blockquote>
+</source>
 
         <p><strong>(2) Programmatic Resource Access</strong></p>
 
         <p>Assume you have a data source reference (discussed in the 
introduction)
         defined in your <code>web.xml</code> like this:</p>
 
-        <blockquote><pre>
+<source>
 &lt;resource-ref&gt;
   &lt;description&gt;Customer Database&lt;/description&gt;
   &lt;res-ref-name&gt;jdbc/CustomerDB&lt;/res-ref-name&gt;
   &lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;
   &lt;res-auth&gt;Container&lt;/res-auth&gt;
 &lt;/resource-ref&gt;
-</pre></blockquote>
+</source>
 
         <p>You can acquire a <code>java.sql.Connection</code> from this data
         source with code like the following (note that the convenience base
         class <code>BaseViewController</code> contains a <code>getBean()</code>
         method that substantially reduces the amount of code needed):</p>
 
-        <blockquote><pre>
+<source>
 FacesContext context = FacesContext.getCurrentInstance();
 ValueBinding vb =
   
context.getApplication().createValueBinding("#{jndi['jdbc/CustomerDB'].connection}");
 Connection conn = (Connection) vb.getValue(context);
-</pre></blockquote>
+</source>
 
         <p>This works by first retrieving the JNDI-configured data source
         instance, and then calling its <code>getConnection()</code> method.
@@ -674,9 +674,9 @@
             for inheritance relationships.  Clay's approach is unique. The
             granularity is targeted at the declaration of JSF components versus
             composition of JSP fragments.
-            <blockquote><pre>
+<source>
 &lt;clay:clay id="address" jsfid="addressPanel"/&gt;
-</pre></blockquote></li>
+</source></li>
         <li>The subtree can be formed using a Tapestry like HTML layout.  HTML
             elements are bound to corresponding JSF components using a
             <code>jsfid</code> attribute. This attribute binds the HTML mock-up
@@ -688,9 +688,9 @@
             standard <code>verbatim</code> (<code>ouputText</code>) component.
             This combines the first option's component definitions
             with the flexibility of using HTML for layout.<br/> 
-           <blockquote><pre>
+<source>
 &lt;clay:clay id="address" jsfid="address.html"/&gt;
-</pre></blockquote></li>
+</source></li>
         <li>The subtree can also be defined at runtime.  The Clay component
             provides a postback validation method event,
             <code>shapeValidator</code>, that can be bound to the associated
@@ -700,9 +700,9 @@
             graph of objects used by the Clay component to build the
             subcomponent tree.   The object's graph is representative of
             the first two declarative approaches.
-            <blockquote><pre>
+<source>
 &lt;clay:clay id="address" jsfid="RUNTIME" 
shapeValidator="#{fullAddress.createSubtree}"/&gt;
-</pre></blockquote></li>
+</source></li>
         </ol>
 
       </subsection>
@@ -723,19 +723,21 @@
         "top-level" elements can be the root of a clay subtree.  The
         <code>componentType</code> attribute defines the association
         to the face's resource.  The <code>jsfid</code> attribute is a
-        logical unique identifier.
-        <blockquote><pre>
+        logical unique identifier.</p>
+
+<source>
 &lt;component jsfid="outputText" 
componentType="javax.faces.HtmlOutputText"/&gt;
 &lt;component jsfid="validateLongRange" 
componentType="javax.faces.LongRange"/&gt;
-</pre></blockquote></p>
+</source>
       
         <p>A <code>component</code> can extend another component, thereby
         inheriting <code>attributes</code> and contained <code>element</code>
         nodes from the parent component.  This is accomplished by using
         the <code>extends</code> attribute.  The  value of the
         <code>extends</code> attribute should be the <code>jsfid</code> of
-        the parent <code>component</code> definition.
-        <blockquote><pre>
+        the parent <code>component</code> definition.</p>
+
+<source>
 &lt;component jsfid="baseLabel" extends="outputLabel" allowBody="false"&gt;
   &lt;attributes&gt;
     &lt;set name="style" value="color:blue"/&gt;
@@ -747,14 +749,15 @@
     &lt;set name="for"   value="city"/&gt;
   &lt;/attributes&gt;
 &lt;/component&gt;
-</pre></blockquote></p>
+</source>
 
         <p>A <code>component</code> node has an attribute container.  This is
         a generic container to hold all <code>attributes</code> that would
         be represented by associated JSF/JSP Tags.  Attributes are added or
         overridden in inheritance using the attribute <code>name</code> as the 
-        unique identifier.      
-        <blockquote><pre>
+        unique identifier.</p>
+
+<source>
 &lt;component jsfid="addressPanel" extends="panelGrid"&gt;
   &lt;attributes&gt;<br/>
     &lt;set name="columns" value="2" /&gt;
@@ -768,7 +771,7 @@
   &lt;/attributes&gt;
   &lt;element renderId="3" jsfid="street1Message"/&gt;
 &lt;/component&gt;
-</pre></blockquote></p>
+</source>
  
        <p>The <code>element</code> node is the composition glue.  Components
        are uniquely defined by a <code>renderId</code> attribute.  This
@@ -777,8 +780,9 @@
        acts as the "method signature" for the <code>element</code> when
        resolving inheritance.  This means components can extend other
        components by overriding or extending elements based on the
-       <code>renderId</code> of the first level of child components. 
-       <blockquote><pre>
+       <code>renderId</code> of the first level of child components.</p>
+
+<source>
 &lt;component jsfid="ssnColumn" extends="column" id="ssn"&gt;
   &lt;element renderId="1" jsfid="outputText" facetName="header"&gt;
     &lt;attributes&gt;
@@ -807,7 +811,7 @@
   &lt;element renderId="0" jsfid="ssnColumn"/&gt;    
   &lt;element renderId="3" jsfid="birthDateColumn"/&gt;    
 &lt;/component&gt;
-</pre></blockquote></p>
+</source>
 
         <p>Clay also allows reuse of view fragments bound to different logical
         managed bean names.  Managed bean names in Shale will most likely
@@ -818,8 +822,9 @@
         "managed-bean-name" is replaced with the value of the Clay
         <code>managedBeanName</code> property.  This preprocessing is
         performed prior to applying the meta attribute values to the target
-        JavaServer Faces component's properties.<br/>
-        <blockquote><pre>
+        JavaServer Faces component's properties.</p>
+
+<source>
 &lt;clay:clay id="saveResidential" managedBeanName="residentialAddress" 
jsfid="saveCommand"/&gt; 
 &lt;clay:clay id="saveBusiness" managedBeanName="businessAddress" 
jsfid="saveCommand"/&gt;
 &lt;component jsfid="saveCommand" extends="commandButton"&gt; 
@@ -830,7 +835,7 @@
   &lt;/attributes&gt;
   &lt;actionListener jsfid="logNavigationActionListener"/&gt;
 &lt;/component&gt;
-</pre></blockquote></p>
+</source>
 
       </subsection>
  
@@ -839,7 +844,269 @@
     <section name="Shale Test Framework">
     <a name="test"/>
     
-      <p>FIXME - Describe Test Framework feature.</p>
+      <a name="test-introduction"/>
+      <subsection name="Introduction">
+
+        <p>Modern application development processes have embraced the idea of
+        <em>unit testing</em> as an integral step in creating high quality
+        software.  In the Java world, a popular framework for building and
+        executing such unit tests is the <a href="http://junit.org";>JUnit</a>
+        framework.  It is straightforward for an application developer to
+        create a corresponding <em>test case</em> class for each class in the
+        application itsef, and ensure that the tests contained in the test case
+        get executed as part of the normal application build process.</p>
+
+        <p>One of the tenets of unit testing is that a test case should focus
+        <em>only</em> on the methods of the class under test, in isolation from
+        related application classes, or APIs provided by any container that the
+        class under test might be installed into at runtime.  But, how do you
+        test an application class that has dependencies on such APIs (such as
+        depending on the Servlet API to provide an 
<code>HttpServletRequest</code>
+        object representing an incoming HTTP request?</p>
+
+        <p>A popular answer to this dilemna is to utilize a library of
+        <em>mock objects</em> -- classes that implement and emulate the 
container
+        APIs, but still run in the isolated environment of a JUnit test case.
+        Shale provides mock object implementations for its own features, as
+        well as features of the underlying container (Servlet
+        and JavaServer Faces) environment.  In addition, convenient base 
classes
+        are provided to make it very easy to build your own test cases 
utilizing
+        these mock objects.  This library is used to create unit tests for 
Shale
+        components itself, but it is primarily focused on making it easy to
+        build unit tests for application classes such as
+        <code>ViewController</code>s.</p>
+
+      </subsection>
+
+      <a name="test-services"/>
+      <subsection name="Provided Services">
+
+        <p>The Shale Test Framework provides mock object libraries, plus base
+        classes for creating your own JUnit <code>TestCase</code>s.</p>
+
+        <p>Mock objects are provided in package 
<code>org.apache.shale.test.mock</code>
+        for the following container APIs:</p>
+        <ul>
+        <li>JavaServer Faces</li>
+        <li>Servlet</li>
+        </ul>
+        <p>These mock object classes implement the majority of the 
functionality
+        defined by the container API Javadocs (although some methods currently
+        throw <code>UnsupportedOperationException</code>).  In addition, many
+        of these classes support public methods, outside of the defined API,
+        for configuring the object in a test environment.  For example,
+        <code>MockServletContext</code> includes 
<code>addInitParameter()</code>
+        and <code>setDocumentRoot()</code> methods, to add context 
initialization
+        parameters to the set returned via <code>getInitParameter()</code> and
+        <code>getInitParameterNames()</code>, and to establish the base 
directory
+        for resolving servlet context resources, respectively.</p>
+
+        <p>The <code>org.apache.shale.test.base</code> package contains 
abstract
+        base classes that wire together instances of the various container API
+        mock objects, in a manner similar to the way they would become 
available
+        at runtime.  The following base classes are available:</p>
+        <ul>
+        <li><code>AbstractJsfTestCase</code> - Base class for unit tests that
+            require Servlet and JavaServer Faces objects to be available.</li>
+        <li><code>AbstractViewControllerTestCase</code> - Extension of
+            <code>AbstractJsfTestCase</code> that also provides convenient
+            utility methods needed to test common scenarios in unit tests for
+            <code>ViewController</code> implementation classes.</li>
+        </ul>
+
+        <p>If you use one of these base classes, the <code>setUp()</code> 
method
+        found there will initialize a set of <code>protected</code> instance
+        variables for the container-managed objects you might need to access.
+        The set of initialized variables includes (variable name and type):</p>
+        <ul>
+        <li><code>application</code> (<code>MockApplication</code>)</li>
+        <li><code>config</code> (<code>MockServletConfig</code>)</li>
+        <li><code>externalContext</code> 
(<code>MockExternalContext</code>)</li>
+        <li><code>facesContext</code> (<code>MockFacesContext</code>)</li>
+        <li><code>lifecycle</code> (<code>MockLifecycle</code>)</li>
+        <li><code>request</code> (<code>MockHttpServletRequest</code>)</li>
+        <li><code>response</code> (<code>MockHttpServletResonse</code>)</li>
+        <li><code>servletContext</code> (<code>MockServletContext</code>)</li>
+        <li><code>session</code> (<code>MockHttpSession</code>)</li>
+        </ul>
+
+      </subsection>
+
+      <a name="test-using"/>
+      <subsection name="Using View Controller">
+
+        <p>The most common scenario for using the Test Framework is to 
construct
+        test cases for <code>ViewController</code> implementation classes.
+        Because the runtime environment of a <code>ViewController</code> is
+        quite constrained, it is easy to construct isolated unit tests that
+        exercise the methods exposed by a <code>ViewController</code> class.
+        The <em>Shale Use Cases</em> web application (included in the 
distribution)
+        contains many examples of such test cases, in the <code>src/test</code>
+        directory.  We will use 
<code>org.apache.shale.usecases.locale.SelectTestCase</code>
+        (which tests the <code>org.apache.shale.usecases.locale.Select</code>
+        implementation) as an example of how such a test case can be 
constructed.</p>
+
+        <ol>
+        <li>Create a new Java class <code>SelectTestCase</code>, in a package
+            directory (typically under <code>src/test</code> in your project)
+            that is the same as the package directory for the class you will be
+            testing.  This allows your test case to access package private and
+            protected variables and methods in the class being tested.</li>
+        <li>Make sure that the package declaration matches that of the class to
+            be tested (in this case, 
<code>org.apache.shale.usecases.locale</code>.</li>
+        <li>Declare your class to extend 
<code>AbstractViewControllerTestCase</code>
+            (or, if you are not testing a <code>ViewController</code> 
implementation,
+            extend <code>AbstractJsfTestCase</code>):
+<source>
+public class SelectTestCase extends AbstractViewControllerTestCase {
+  ...
+}
+</source></li>
+        <li>Create a constructor that takes a <code>String</code> parameter, 
and
+            passes it to the superclass constructor:
+<source>
+public SelectTestCase(String name) {
+    super(name);
+}
+</source></li>
+        <li>Create a <code>setUp()</code> method and <strong>be sure</strong>
+            to call <code>super.setUp()</code> at the beginning.  This method
+            will be called by JUnit immediately before it executes each
+            test method.
+<source>
+public void setUp() {
+    super.setUp();
+    // Customization will go here
+}
+</source></li>
+        <li>After the call to the superclass <code>setUp()</code> method,
+            perform any other initialization required to execute the tests
+            in this test case.  In our example case, a configuration method
+            on the <code>MockApplication</code> instance will be used to
+            define the default and supported <code>Locale</code>s for this
+            set of tests.  This corresponds to what would happen at runtime,
+            when the JavaServer Faces initialization process used the contents
+            of the <code>/WEB-INF/faces-config.xml</code> resource to 
initialize
+            these values.  In addition, we will create a new instance of the
+            <code>Select</code> class to be tested.  It is important to create
+            a new instance for each test, to ensure that execution of one test
+            does not get influenced by the leftover property settings from a
+            previous test.
+<source>
+public void setUp() {
+    super.setUp();
+
+    // Configure the supported locales for this application
+    List list = new ArrayList();
+    list.add(new Locale("en"));
+    list.add(new Locale("fr"));
+    list.add(new Locale("de"));
+    list.add(new Locale("es"));
+    application.setSupportedLocales(list);
+
+    // Construct a new ViewController instance
+    vc = new Select();
+
+}
+</source></li>
+        <li>Create a static <code>suite()</code> method that identifies the
+            test methods to be provided by this test case.  The simplest
+            approach is to leverage a constructor of the <code>TestSuite</code>
+            class that accepts the <code>Class</code> instance for this test
+            suite:
+<source>
+public static suite() {
+    return new TestSuite(SelectTestCase.class);
+}
+</source></li>
+        <li>Create a <code>tearDown()</code> method that cleans up any custom
+            variables you allocated in your <code>setUp()</code> method, and
+            then calls the <code>super.tearDown()</code> method.  This will be
+            called by JUnit after each test is executed.
+<source>
+public void tearDown() {
+    vc = null;
+    super.tearDown();
+}
+</source></li>
+        <li>Declare the custom instance variable(s) that you are setting up
+            in your <code>setUp()</code> method.  In this case, we create an
+            instance of the <code>ViewController</code> class to be tested.
+            A new instance will be created (via a call from JUnit to the
+            <code>setUp()</code> method) before each test method is executed.
+<source>
+// The instance to be tested
+Select vc = null;
+</source></li>
+        <li>Create one or more individual test methods (which must be
+            <code>public</code>, return <code>void</code>, take no arguments,
+            and have a method name of the form <code>testXXXX</code>.  For
+            advice on how to construct such methods, consult the
+            <a href="http://junit.org/";>JUnit Web Site</a>, or any of the
+            large number of resources on the web describing how to use JUnit
+            to build unit tests.  The following example tests what happens
+            when the <code>select()</code> method (which is executed when
+            the <em>Go</em> button is pressed), but the value entered is not
+            one of the valid options.  <strong>NOTE</strong> that the test
+            method must emulate the runtime calls to the 
<code>ViewController</code>
+            event methods, because there is no actual runtime container
+            available to perform these tasks automatically:
+<source>
+// Test behavior of select() with an invalid value
+public void testSelectInvalid() {
+
+    Locale locale = new Locale("en");
+    facesContext.getViewRoot().setLocale(locale);
+    vc.init();
+    vc.preprocess();
+    vc.setLocale("it");
+    String result = vc.select();
+    assertEquals(Select.FAILURE, result);
+    checkMessageCount(1);
+    assertEquals(locale, facesContext.getViewRoot().getLocale());
+
+}
+</source>
+            The test case sets the <code>locale</code> property (which is
+            bound to a dropdown component at runtime, but we are simulating
+            the behavior of Update Model Values here) to an invalid value,
+            then calls the <code>select()</code> method.  The test then
+            verifies that the logical outcome returned matches that which
+            is expected (<code>Select.FAILURE</code>), that there was an error
+            message queued to be displayed, and that the <code>locale</code>
+            for the current view was <strong>NOT</strong> actually changed.
+            <br/></li>
+        <li>Finally, integrate the execution of this test case into your
+            build script.  Many IDEs will take care of this for you; however,
+            if you are creating an Ant build script by hand, you might find
+            the <code>test</code> target from the Shale Use Cases example
+            a useful starting point.  It locates <em>all</em> the test cases
+            related to the entire application, and executes them:
+<source>
+  &lt;target name="test" depends="test.compile"
+   description="Execute unit tests">
+
+    &lt;mkdir          dir="${build.home}/test-results"/>
+
+    &lt;echo       message="Running unit tests ..."/>
+    &lt;junit printSummary="no" fork="yes"
+          haltonfailure="yes" haltonerror="yes">
+      &lt;classpath  refid="test.classpath"/>
+      &lt;formatter   type="plain"
+                usefile="false"/>
+      &lt;formatter   type="xml"
+                usefile="true"/>
+      &lt;batchtest todir="${build.home}/test-results">
+        &lt;fileset    dir="${build.home}/test-classes"
+               includes="org/apache/shale/usecases/*/*TestCase.class"/>
+      &lt;/batchtest>
+    &lt;/junit>
+
+  &lt;/target>
+</source></li>
+        </ol>
+
+      </subsection>
 
     </section>
 



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to