<?xml version="1.0"?>
<!--
  Copyright 2002,2004 The Apache Software Foundation.
  
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
  
       http://www.apache.org/licenses/LICENSE-2.0
  
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->

<document>
  <properties>
    <title>JellyUnit</title>
    <author email="jstrachan@apache.org">James Strachan</author>
  </properties>

  <body>
    <section name="JellyUnit"> 
      <p>
        JellyUnit is a Jelly based JUnit testing mechanism. 
        This allows Jelly scripts to be used to perform unit testing which can be particularly useful
        if you wish to test XML, XPath, SQL, HTTP, JMS or SOAP interactions.
      </p>
      <p>
        JellyUnit works by using the <a href="libs/junit/tags.html">JUnit library </a> in a Jelly script
        to create JUnit TestSuite and TestCase objects. 
        There are all the usual JUnit assertion tests available such as &lt;assert&gt; 
        &lt;assertEquals&gt; and &lt;fail&gt;. You can use both Jexl and XPath expressions in the 
        &lt;assert&gt; tag via either the <i>test</i> or the <i>xpath</i> attributes.
      </p>
      <p>
        Inside these test scripts you can use the full range of Jelly tags such as navigating over
        XML test data creating multiple test cases based on sample data, performing SQL operations, SOAP calls, 
        HTTP or JMS requests etc. 
      </p>
      <p>
        You can also use Ant FileSets and the &lt;fileScanner&gt; tag to iterate over collections of 
        Jelly scripts or XML data files and use this data to define new test cases.
      </p>
    </section>
    
    <section name="Examples"> 
      <p>
        There is a simple example JellyUnit script
        <a href="http://cvs.apache.org/viewcvs.cgi/jakarta-commons/jelly/jelly-tags/junit/src/test/org/apache/commons/jelly/tags/junit/suite.jelly?rev=HEAD">here</a>
      </p>
      <p>
        An example demonstrating the use of the <a href="libs/betwixt/tags.html">Betwixt</a> library is 
        <a href="http://cvs.apache.org/viewcvs.cgi/jakarta-commons/jelly/jelly-tags/betwixt/src/test/org/apache/commons/jelly/betwixt/suite.jelly?rev=HEAD">here</a>
        along with a common shared test script
        <a href="http://cvs.apache.org/viewcvs.cgi/jakarta-commons/jelly/jelly-tags/betwixt/src/test/org/apache/commons/jelly/betwixt/common.jelly?rev=HEAD">here</a>
      </p>
      <p>
          The <a href="libs/validate/tags.html">validate</a> library can be used to perform XML validation inside JellyUnit.
          For example there's an example JellyUnit script validating XML 
          <a href="http://cvs.apache.org/viewcvs/jakarta-commons/jelly/jelly-tags/validate/src/test/org/apache/commons/jelly/tags/validate/suite.jelly?rev=HEAD">here</a>
      </p>
    </section>

    <section name="Mock Tags"> 
      <p>
        In unit testing scenarios its often useful to use 
        <a href="http://c2.com/cgi/wiki?MockObject">Mock Objects</a> to test application logic and stub the behaviour
        of other service
      </p>
      <p>
        JellyUnit supports a feature called <i>Mock Tags</i> which are very similar to Mock Objects. 
        Mock Tags were invented by by Joe Walnes.
      </p>
      <p>
        Essentially the technique is to mock, or stub the behaviour of Jelly tags so that they give the results that you expect
        from services.
        For example imagine you had a Jelly script with tags which worked with databases or web services.
        You could use mock tags to stub what the tags are meant to do, to test your script invokes them correctly
        without requiring the underlying services
      </p>
      <p>
        There's an and example of using Mock Tags via the <a href="libs/define/tags.html">define</a> library 
        <a href="http://cvs.apache.org/viewcvs.cgi/jakarta-commons/jelly/jelly-tags/define/src/test/org/apache/commons/jelly/tags/mock/suite.jelly?rev=HEAD">here</a>
        which creates the mock tags, inside a JellyUnit test case and then invokes this example 
        <a href="http://cvs.apache.org/viewcvs.cgi/jakarta-commons/jelly/jelly-tags/define/src/test/org/apache/commons/jelly/tags/mock/service.jelly?rev=HEAD">service</a>
        using the mock tags rather than the underlying SQL and web service tags.
        Running the same service from outside of the Mock Tags JellyUnit test case would use the real tag implementations.
      </p>
    </section>
    

    <section name="Integration with TestRunners"> 
      <p>
        To integrate cleanly inside JUnit TestRunner frameworks there is a helper class,
        <a href="libs/junit/apidocs/org/apache/commons/jelly/tags/junit/JellyTestSuite.html">JellyTestSuite</a>
        which you can derive from
        to produce a single Java class which has a static <i>suite()</i> method to create a TestSuite object 
        containing all the test cases created by the JellyUnit files.
        There is an 
        <a href="http://cvs.apache.org/viewcvs.cgi/jakarta-commons/jelly/jelly-tags/junit/src/test/org/apache/commons/jelly/junit/TestJUnit.java?rev=HEAD">example</a>
        of this in action.
      </p>
      <p>So if you had a test suite defined in a jelly script <a>suite.jelly</a> in a package com.acme.foo
          then you could create a class, capable of being ran inside any JUnit test runner framework as follows
      </p>
<source>
package com.acme.foo;
      
import junit.framework.TestSuite;

import org.apache.commons.jelly.tags.junit.JellyTestSuite;

/** 
 * A helper class to run jelly test cases in a JUnit TestRunner
 */
public class TestFoo extends JellyTestSuite {

    public static TestSuite suite() throws Exception {
        return createTestSuite(TestFoo.class, "suite.jelly");        
    }
}
</source>
    </section>
  </body>
</document>

