<?xml version="1.0"?>

<!--
 * ========================================================================
 * 
 * Copyright 2001-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 id="howto_testcase">

  <properties>
    <title>Writing Cactus TestCase</title>
  </properties>

  <body>

    <section title="Introduction">

      <p>
        This tutorial explains how to write a test case, using Cactus. There
        are several types of test cases: test cases for writing servlet
        unit tests, test cases for writing taglib unit tests and test cases
        for writing filter unit tests. We will first cover the principles
        which are generic to all test cases and then we will dive into
        the details specific to each test case.
      </p>
      <ul>
        <li>
          <jump anchor="general_principles">General principles</jump>
        </li>
        <li>
          <jump anchor="specific_details">TestCase specific details</jump>
        </li>
      </ul>

      <note>
        In order to help writing test case we highly suggest to have a look
        at the examples provided as part of the Cactus distribution. Also,
        all the best practices for JUnit also applies to Cactus test cases
        as they are in essence JUnit test cases.
      </note>

    </section>

    <anchor id="general_principles"/>
    <section title="General principles">

      <p>
        To write a test case, please follow the steps defined below.
      </p>

      <section title="Step 1: Imports">

        <p>
          You need to include the following imports in your test class (
          <code>junit.framework.*</code> is needed because Cactus uses JUnit
          as the client side application for calling the tests):
        </p>

<source><![CDATA[
import org.apache.cactus.*;
import junit.framework.*;
]]></source>

      </section>

      <section title="Step 2: Extend a Cactus TestCase class or reuse a JUnit TestCase">
        
        <section title="Option A: Extend a Cactus TestCase class">
  
          <p>
            We need to create a class (our test class) that extends one of
            Cactus test cases, depending on what we are testing:
          </p>
          <ul>
            <li>
              <strong><code>ServletTestCase</code></strong>: extend this class
              for writing tests for unit testing code that uses Servlet API
              objects (<code>HttpServletRequest</code>,
              <code>HttpServletResponse</code>, <code>HttpSession</code>,
              <code>ServletConfig</code>, <code>ServletContext</code>, ...),
              like Servlets or any java classes which have methods that
              manipulates Servlet API objects. For example:<br/><br/>
<source><![CDATA[
public class TestSampleServlet extends ServletTestCase
{
]]></source>
              <br/>
            </li>
            <li>
              <strong><code>JspTestCase</code></strong>: extend this class for
              writing tests for unit testing code that uses JSP API objects
              (<code>PageContext</code>, <code>JspWriter</code>, ...), like
              Taglibs or any java classes which have methods that manipulates
              JSP API objects. For example:<br/><br/>
<source><![CDATA[
public class TestSampleTag extends JspTestCase
{
]]></source>
              <br/>
            </li>
            <li>
              <strong><code>FilterTestCase</code></strong>: extend this class
              for writing tests for unit testing code that uses Filter API
              objects (<code>FilterChain</code>, <code>FilterConfig</code>,
              <code>HttpServletRequest</code>, <code>HttpServletResponse</code>,
              ...), like Filters or any java classes which have methods that
              manipulates Filter API objects. For example:<br/><br/>
<source><![CDATA[
public class TestSampleFilter extends FilterTestCase
{
]]></source>
              <br/>
            </li>
          </ul>
  
        </section>
  
        <section title="Option B: reuse a JUnit TestCase">
  
          <p>
            Cactus is able to run pure JUnit TestCase on the server side.
            This is done by using the <code>ServletTestSuite</code> Test Suite
            that wraps your existing Test Cases. For example:<br/><br/>
<source><![CDATA[
public class TestJUnitTestCaseWrapper extends TestCase
{
    public static Test suite()
    {
        ServletTestSuite suite = new ServletTestSuite();
        suite.addTestSuite(TestJUnitTestCaseWrapper.class);
        return suite;
    }

    public void testXXX()
    {
    }
}
]]></source>
          </p>
        </section>
  
      </section>

      <section title="Step 3 (optional): setUp() and tearDown() methods">

        <p>
          As in JUnit, you can define a <code>setUp()</code> and a
          <code>tearDown()</code> methods. They are executed respectively
          before and after each test case. However, whereas in JUnit they are
          executed on the client side, in Cactus they are executed on the
          server side. It means that you will be able to access the Cactus
          implicit object (these are the objects from the API as described
          in Step 2) within them. In other words, you'll be able to do
          things such as putting a value in the HTTP Session prior to calling
          the test cases, etc.
        </p>
        <p>
          As in JUnit, the <code>setUp()</code> and <code>tearDown()</code>
          methods are optional.
        </p>

      </section>

      <section title="Step 4 (optional): begin() and end() methods">

        <p>
          <code>begin(...)</code> and <code>end(...)</code> methods are the
          client side equivalent of the <code>setUp()</code> and a
          <code>tearDown()</code> methods (see previous step). They are called
          on the client side, before and after every test.
        </p>
        <p>
          The <code>begin()</code> and <code>end()</code>
          methods are optional.
        </p>

      </section>

      <section title="Step 5: testXXX() methods">

        <p>
          As in JUnit, the main method for a test is the
          <code>testXXX()</code> method. The difference being that these
          methods are executed in the container with Cactus. Each XXX test
          case must have a <code>testXXX()</code> method defined.
        </p>
        <p>
          In your <code>testXXX()</code> methods you will:
        </p>
        <ul>
          <li>
            instantiate the class to test (you can also factor this instance
            out and define is as a class instance variable),
          </li>
          <li>
            setup any server-side domain object (like putting a variable in
            the Http session, ...). Indeed, the Cactus test case class that
            you have extended in Step 2 has several instance variables (they
            are the different API objects mentioned in Step 2) that it has
            initialised with valid objects. Depending on the test case class
            that you have extended these variables are <code>request</code>
            (of type <code>HttpServletRequest</code>),
            <code>config</code> (of type <code>ServletConfig</code> for
            <code>ServletTestCase</code> or of type <code>FilterConfig</code>
            for <code>FilterTestCase</code>), ... (see the "Testcase Specific
            Details" Step below),
          </li>
          <li>
            call the method to test,
          </li>
          <li>
            perform JUnit standard asserts (<code>asserts(..)</code>,
            <code>assertEquals(...)</code>, <code>fail(...)</code>, ...) to
            verify that the test was successful
          </li>
        </ul>
        <p>
          For example:
        </p>

<source><![CDATA[
public void testXXX()
{
    // Initialize class to test
    SampleServlet servlet = new SampleServlet();

    // Set a variable in session as the doSomething() method that we are testing need
    // this variable to be present in the session (for example)
    session.setAttribute("name", "value");

    // Call the method to test, passing an HttpServletRequest object (for example)
    String result = servlet.doSomething(request);

    // Perform verification that test was successful
    assertEquals("something", result);
    assertEquals("otherValue", session.getAttribute("otherName"));
}
]]></source>

      </section>

      <section title="Step 6 (optional): beginXXX() methods">

        <p>
          For each XXX test case, you can define a corresponding
          <code>beginXXX()</code> method (optional). You will use it to
          initialize HTTP related parameters (HTTP parameters, cookies,
          HTTP headers, URL to simulate, ...). You will be able to retrieve
          these values in your <code>testXXX()</code> by calling the different
          API of <code>HttpServletRequest</code> (like
          <code>getQueryString()</code>, <code>getCookies()</code>,
          <code>getHeader()</code>, ...).
        </p>
        <p>
          The signature of the begin method is:
        </p>

<source><![CDATA[
public void beginXXX(WebRequest theRequest)
{
  [...]
}
]]></source>

        <p>
          where <code>theRequest</code> is the object (provided by Cactus)
          that you use to set all the HTTP related parameters.
        </p>
        <p>
          The full description of all the HTTP related parameters that you can
          set can be found in the javadoc for the <code>WebRequest</code>
          interface. You should also check the examples provided as part of the
          Cactus distribution.
        </p>
        <p>
          The <code>beginXXX()</code> methods are executed on the client
          side, prior to executing <code>testXXX()</code> on the server side
          and thus, do not have access to any of the class variables that
          represent API objects (their values are <code>null</code>)
        </p>

      </section>

      <anchor id="endxxx"/>
      <section title="Step 7 (optional): endXXX() methods">

        <p>
          For each XXX test case, you can define a corresponding
          <code>endXXX()</code> method. You will use this method to
          verify the returned HTTP related parameters from your test case
          (like the returned content of the HTTP response, any returned
          cookies, returned HTTP headers, ...).
        </p>
        <p>
          For versions of Cactus up to v1.1, the signature of the end
          method is:
        </p>

<source><![CDATA[
public void endXXX(HttpURLConnection theConnection)
{
  [...]
}
]]></source>

        <p>
          ... and some helper methods to extract the response content and
          cookies were provided in the <code>AssertUtils</code> class
          (see javadoc).
        </p>
        <p>
          However, beginning with Cactus 1.2, this signature has been
          deprecated. There are now 2 possible signatures for the end
          method, depending on whether you need to perform sophisticated
          checks on the content of what is returned or not. For complex
          checking, we have integrated with the
          <link href="http://httpunit.sourceforge.net">HttpUnit</link>
          framework. See the
          <link href="site:howto_httpunit">HttpUnit tutorial</link> for the
          end method signatures and a full description.
        </p>
        <p>
          The <code>endXXX()</code> methods are executed on the client
          side, after executing <code>testXXX()</code> on the server side
          and thus, do not have access to any of the class variables that
          represent API objects (their values are <code>null</code>)
        </p>

      </section>

    </section>

    <anchor id="specific_details"/>
    <section title="TestCase specific details">

      <p>
        <strong>Before reading any of the following detailed tutorials,
        make sure you have read the previous general principles.</strong>
      </p>
      <ul>
        <li>
          <link href="site:howto_testcase_servlet">ServletTestCase
          principles</link>,
        </li>
        <li>
          <link href="site:howto_testcase_jsp">JspTestCase
          principles</link>,
        </li>
        <li>
          <link href="site:howto_testcase_filter">FilterTestCase
          principles</link>
        </li>
      </ul>

    </section>

  </body>
</document>
