You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2003/01/20 16:06:03 UTC
cvs commit: jakarta-tapestry/doc/src/ContributorsGuide ContributorsGuide.xml
hlship 2003/01/20 07:06:03
Modified: doc/src/ContributorsGuide ContributorsGuide.xml
Log:
Update Contributor's Guide with more information on how to add JUnit tests.
Revision Changes Path
1.13 +320 -24 jakarta-tapestry/doc/src/ContributorsGuide/ContributorsGuide.xml
Index: ContributorsGuide.xml
===================================================================
RCS file: /home/cvs/jakarta-tapestry/doc/src/ContributorsGuide/ContributorsGuide.xml,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- ContributorsGuide.xml 16 Jan 2003 01:16:50 -0000 1.12
+++ ContributorsGuide.xml 20 Jan 2003 15:06:03 -0000 1.13
@@ -66,18 +66,27 @@
<chapter id="cvs">
<title>CVS Access</title>
-
+
<para>
+<warning>
+<title>We've Moved to Jakarta</title>
+<para>
+Some of the details are in transition, with the move from SourceForge
+to Jakarta. The new server location is <literal>cvs.apache.org</literal>,
+the repository path is <literal>/home/cvs</literal> and
+the module is <literal>jakarta-tapestry</literal>.
+</para>
+</warning>
Tapestry is housed at the &TapestryProjectPage;. Read-only CVS access is available
to anyone; to have read-write access you must be registered
with SourceForge, and then contact the Tapestry administrator
-(<ulink url="mailto:hship@users.sf.net">Howard Lewis Ship</ulink>) to be
+(<ulink url="mailto:hlship@apache.org">Howard Lewis Ship</ulink>) to be
added to the list of Tapestry developers.
</para>
<para>
Using Eclipse, obtaining the source code takes only a few steps. Tapestry
-compiles using some libraries from &JBoss; 3.0.0, which must be downloaded first.
+compiles using some libraries from &JBoss; 3.0.4, which must be downloaded first.
</para>
<para>
@@ -148,7 +157,7 @@
<para>
To perform a full build from the command line, you must have
JDK 1.3 or better installed, as well
-as &JBoss; 3.0.0.
+as &JBoss; 3.0.4.
</para>
<para>
@@ -426,7 +435,7 @@
<listitem>
<para>
-Download &Fop; 0.20.4rc and unpack into a permanent directory.
+Download &Fop; 0.20.4 and unpack into a permanent directory.
</para>
</listitem>
@@ -460,6 +469,54 @@
</section>
+<section id="building.clover-setup">
+ <title>Clover Setup</title>
+
+<para>
+<ulink url="http://www.thecortex.net/clover">Clover</ulink> is a properietary tool
+that gathers code coverage information and generates reports from it. They
+have kindly donated a license for Clover to the Tapestry project.
+</para>
+
+<para>
+To configure for clover:
+<itemizedlist>
+
+<listitem>
+<para>Extract the Clover distribution, <filename>support/clover.zip</filename>
+to a non-temporary directory.
+</para>
+</listitem>
+
+<listitem>
+<para>
+Modify <filename>config/build.properties</filename> and add an entry
+for <literal>clover.dir</literal>. As usual, provide the absolute
+pathname to the Clover directory, using only forward slashes.
+</para>
+</listitem>
+
+<listitem>
+<para>
+Copy <filename>clover.jar</filename> to the
+<filename><replaceable>Ant</replaceable>/lib</filename> directory.
+</para>
+</listitem>
+
+</itemizedlist>
+</para>
+
+
+<para>
+The Clover report executes from the <filename>junit</filename> directory, using the Ant
+target <literal>clover</literal>. It runs builds the clover-enhanced version of the framework
+classes, and executs the JUnit test suite twice (with all logging enabled and all logging disabled),
+then generates the HTML report into the
+<filename>web/doc/clover</filename> directory.
+</para>
+
+</section>
+
</chapter>
<chapter id="standards">
@@ -570,7 +627,7 @@
Collections (from package <literal>java.util</literal>) should be documented to identify
the type of object stored, and for <classname>Map</classname>
the type of key. Example: <literal>List of {@link IRender}</literal>, or
-<literal>{@link Map} of {@link IBinding} keyed on String name</literal>.
+<literal>Map of {@link IBinding} keyed on String name</literal>.
</para>
<para>
@@ -714,18 +771,19 @@
<para>
-The minor version represents the introduction of new functionality and bug fixes
+The minor version represents a milestone release, encompassing
+the introduction of new functionality and bug fixes
in a stable manner. <literal>2.1</literal> or <literal>2.2</literal> would be examples
-of minor releases.
+of milestone releases.
</para>
<para>
-An incremental release represents a transition from one minor release to the next.
+An incremental release represents a transition from one milestone release to the next.
Incremental releases are <literal>alpha</literal>, <literal>beta</literal> or
<literal>rc</literal> (release candidate).
-Typically, after a major release there will
+Typically, after a milestone release there will
be a series of alpha, then beta, then rc releases, leading up to
-the next minor release.
+the next milestone release.
A possible sequence is <literal>2.1</literal>, <literal>2.2-alpha-1</literal>,
<literal>2.2-beta-1</literal>, <literal>2.2-rc-1</literal>, <literal>2.2</literal>.
</para>
@@ -811,10 +869,24 @@
<section id="procedures.junit">
<title>JUnit Tests</title>
+
+<para>
+Tapestry has an excellent JUnit test suite, with code coverage
+figures over 70% at the time of this writing (2.4-alpha-2). It is
+<emphasis>required</emphasis> that changes to the framework
+be accompanied by additional JUnit tests (typically, mock tests; see
+below) to validate the changes. In addition, there is an ongoing
+effort to fill in the gaps in the existing suite; the suite should reach
+over 90% code coverage.
+</para>
+
<para>
-Where possible, create JUnit tests for your code. At the time of this writing, there isn't a procedure for
-directly testing Tapestry components ... however, you should often be able to test other objects
-related to your components, such as helper beans, models, etc.
+Some of the JUnit tests now require &Jython;. You must
+download and install Jython 2.1,
+then configure <literal>jython.dir</literal> in <filename>config/build.properties</filename>
+to point to the install directory. As usual, use an absolute path and forward slashes only. To run
+the JUnit test suite within Eclipse, you must
+set the <literal>JYTHON_DIR</literal> classpath variable.
</para>
<para>
@@ -823,11 +895,188 @@
</para>
<para>
-Work is underway to allow unit testing of components using
-a <emphasis>mock</emphasis> Servlet API, but this will
-not be available until Tapestry release 2.3.
+Less than half of Tapestry is tested using traditional JUnit tests. The majority of JUnit testing occurs using
+a system of mock unit tests. Mock testing involves replacing the key classes of the
+Servlet API (<classname>HttpServletRequest</classname>, <classname>HttpSession</classname>, etc.) with
+out own implementations, with extensions that allow for checks and validations. Instead of processing a series of
+requests over HTTP, the requests are driven by an XML script file, which includes output checks.
+</para>
+
+<para>
+Generally, each bit of functionality can be tested using its own mini-application.
+Create the application as
+<filename>junit/context<replaceable>X</replaceable></filename>. This is much easier now, using Tapestry 2.4 features
+such as dynamic lookup of specifications and implicit components.
+</para>
+
+<para>
+Create a test script in the <filename>net.sf.tapestry.junit.mock</filename> package. Add a method to
+the <classname>MockTestCase</classname> class.
+</para>
+
+<programlisting>
+public void test<replaceable>Name</replaceable>()
+throws Exception
+{
+ attempt("Test<replaceable>Name</replaceable>.xml");
+}
+</programlisting>
+
+<note>
+<para>
+The XML script is not validated, and invalid elements are
+generally ignored. The class <classname>MockTester</classname>
+performs the test, and its capabilities are in fluxx, with
+new capabilities being added as needed.
+</para>
+</note>
+
+<para>
+A test script consists of an <sgmltag class="starttag">mock-test</sgmltag>
+element. Within it, the virtual context and servlet are defined.
+</para>
+
+<programlisting>
+<![CDATA[
+<mock-test>
+ <context name="c6" root="context6"/>
+
+ <servlet name="app" class="net.sf.tapestry.ApplicationServlet">
+ <init-parameter name="net.sf.tapestry.engine-class"
+ value="net.sf.tapestry.junit.mock.c6.C6Engine"/>
+ </servlet>
+]]>
+</programlisting>
+
+<para>
+The name for the context becomes the leading term in any
+generated URLs. Likewise, the servlet name becomes the second
+term. The above example will generate URLs that reference
+<literal>/c6/app</literal>. Specifying a <literal>root</literal>
+for a context identifies the root context directory (beneath the top level
+<filename>junit</filename> directory). In this example, HTML templates
+go in <filename>context6</filename> and specifications
+go in <filename>context6/WEB-INF</filename>.
+</para>
+
+<para>
+Following the <sgmltag class="starttag">servlet</sgmltag>
+and <sgmltag class="starttag">context</sgmltag> elements, a series
+of <sgmltag class="starttag">request</sgmltag> elements. Each such element
+simulates a request. A request specifies any query parameters passed as part
+of the request, and contains a number of assertions that test
+either the results, generally in terms of searching for strings
+or regular expressions within the HTML response.
</para>
+<programlisting>
+<![CDATA[
+<request>
+ <parameter name="service" value="direct"/>
+ <parameter name="context" value="0/Home/$DirectLink"/>
+
+ <assert-output name="Page Title">
+<![CDATA[
+<title>Persistant Page Property</title>
+]]>]]><![CDATA[
+ </assert-output>
+]]>
+</programlisting>
+
+<warning>
+<para>
+As in the above example, it is very important
+that HTML tags be properly escaped with the XML CDATA construct.
+</para>
+</warning>
+
+<para>
+Adding <literal>failover="true"</literal> to the
+<sgmltag class="starttag">request</sgmltag> simulates a failover. The contents
+of the &HttpSession; are serialized,
+then deserialized. This ensures that all the data stored into the
+&HttpSession; will survive a failover to a new server within
+a cluster.
+</para>
+
+<para>
+All of the assertion elements expect a <literal>name</literal>
+attribute, which is incorporated into any error message
+if the assertion fails (that is, if the expected output
+is not present).
+</para>
+
+
+<para>
+The <sgmltag class="starttag">assert-output</sgmltag> element checks for the
+presence of the contained literal output, contained within the
+element. Leading and trailing whitespace is trimmed before
+the check is made.
+</para>
+
+<programlisting>
+<![CDATA[
+ <assert name="Session Attribute"
+ expression='request.session.getAttribute("app/Home/message").equals("Changed")'
+ />
+]]>
+</programlisting>
+
+<para>
+The <sgmltag class="starttag">assert</sgmltag> element checks
+that the provided OGNL expression evaluates to true.
+</para>
+
+<programlisting>
+<![CDATA[
+ <assert-regexp name="Error Message">
+<![CDATA[
+<span class="error">\s*You must enter a value for Last Name\.\s*</span>
+]]>]]><![CDATA[
+ </assert-regexp>
+]]>
+</programlisting>
+
+<para>
+The <sgmltag class="starttag">assert-regexp</sgmltag> looks
+for a regular expression in the result, instead of a simple literal
+string.
+</para>
+
+<programlisting>
+<![CDATA[
+ <assert-output-matches name="Selected Radio" subgroup="1">
+<![CDATA[
+<input type="radio" name="inputSex" checked="checked" value="(.*?)"/>
+]]>]]><![CDATA[
+ <match>1</match>
+ </assert-output-matches>
+]]>
+</programlisting>
+
+<para>
+The <sgmltag class="starttag">assert-output-matches</sgmltag>
+is the most complicated assertion. It contains a regular expression
+which is evaluated. For each match, the subgroup value is extracted,
+and compared to the next <sgmltag class="starttag">match</sgmltag>
+value. Also, the count of matches (vs. the number of
+<sgmltag class="stattag">match</sgmltag> elements) is checked.
+</para>
+
+
+
+<note>
+<title>Force a failure, then check for correctness</title>
+<para>
+Sometimes the tests themselves have bugs. A useful technique is
+to purposely break the test to ensure that it is checking for what
+it should check, then fix the test. For example, adding <literal>XXX</literal>
+into a <sgmltag class="starttag">assert-output</sgmltag>. Run the test suite
+and expect a failure, then remove the <literal>XXX</literal> and
+re-run the test, which should succeed.
+</para>
+</note>
+
</section>
<section id="procedures.documentation">
@@ -848,6 +1097,15 @@
<section id="procedures.component-doc">
<title>Component Documentation</title>
+<warning>
+<para>
+This section is out of date. In general, each component should
+include a link to the Component Reference page for the component.
+The Component Reference page has a format and content
+similar to what's listed here.
+</para>
+</warning>
+
<para>
Although there is limited documentation about components in their component specification file, that documentation
is designed to be a short reminder, not the complete documentation. Full documentation goes into
@@ -985,14 +1243,52 @@
<title>Creating Examples</title>
<para>
-In lieu of unit tests, the best way to make sure a new component works (as well as advertise
-its existence) is to update the Tapestry Tutorial to include it; typically the Tapestry Workbench.
-The Workbench is very easy to extend with new pages, it also has
-the <emphasis>very</emphasis> useful feature for dumping out
-the request context on each request which greatly simplifies debugging links and form components.
+Extending the Workbench application to demonstrate new features or components
+is expected for any significant changes or additions to the framework, or
+to the contrib library.
</para>
</section>
+
+<section id="procedures.copyrights">
+ <title>Updating Copyrights</title>
+
+<para>
+All source code stored in the repository must contain the standard Apache copyright and license. A copy of the
+license, as a comment block, is stored as <filename>support/license.txt</filename>
+</para>
+
+<para>
+The contents of this file can be pasted in directly before the <literal>package</literal> statement of a Java source file.
+</para>
+
+<para>
+Alternately, a <ulink url="http://www.python.org">Python</ulink> script is provided which
+can locate all Java source files within a directory tree and ensure that the leading comment block
+is correct. It modifies any source files where the leading comment doesn't match, but does not modify
+any files where the leading comment matches.
+</para>
+
+<para>
+To use the script, change to the <filename>support</filename> directory and execute the command
+<command>python update-copyrights.py copyright.txt <replaceable>directory</replaceable></command>.
+</para>
+
+<para>
+The script is very fast, simply using <literal>..</literal> as the directory works in only a few seconds.
+</para>
+
+<warning>
+<title>Cygwin Python</title>
+<para>
+On my computer (running Windows XP and/or 2000), when using the
+<ulink url="http://sources.redhat.com/cygwin">Cygwin</ulink>
+version of Python, it is necessary to execute the script
+from the Bash shell, not the standard Windows command line.
+</para>
+</warning>
+
+</section> <!-- procedures.copyrights -->
</chapter>