<?xml version="1.0" encoding='ISO-8859-1'?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
  "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
  <!ENTITY % cartoweb SYSTEM "../cartoweb.ent" >
  %cartoweb;
]>

<!-- $Id: unit_test.xml,v 1.10 2007-07-26 15:15:12 olivier Exp $ -->

<chapter id="dev.unit_test">
 <title>Unit Tests</title>

 <sect1 id="dev.unit_test.intro"> 
  <title>Introduction</title>
  <para>
    Unit tests are an important componant in the &cartoweb; development 
    environment. 
    The framework used for unit testing is based on  
      <ulink url="http://www.phpunit.de/en/index.php">PHPUnit2</ulink>,
   a <acronym>PEAR</acronym> package.
   For more informations abouth PHPUnit2, see <ulink 
   url="http://pear.php.net/reference/PHPUnit2-2.0.3/">http://pear.php.net/reference/PHPUnit2-2.0.3/</ulink>
  </para>
<!--
  <para>
   Unit tests are a powerful way to implement automated tests. 
   Please consider writing tests directly while coding.
  </para>
  -->
  <para>
    PHPUnit2 is included in the libraries shipped with &cartoweb;. Thus, no 
    installation is needed to run and write new tests.
  </para>
 </sect1>

<!--
 <sect1 id="dev.unit_test.install"> 
  <title>Installing PHPUnit2</title>
  <para>
   PHPUnit2 requires the installation of several PEAR packages:
   <itemizedlist>
    <listitem>
     <para>
      PEAR: <ulink 
      url="http://pear.php.net/package/PEAR">http://pear.php.net/package/PEAR</ulink>
     </para>
    </listitem>
    <listitem>
     <para>
      PHPUnit2: <ulink 
      url="http://pear.php.net/package/PHPUnit2">http://pear.php.net/package/PHPUnit2</ulink>
     </para>
    </listitem>
    <listitem>
     <para>
      Benchmark: <ulink 
      url="http://pear.php.net/package/Benchmark">http://pear.php.net/package/Benchmark</ulink>
     </para>
    </listitem>
    <listitem>
     <para>
      Console_Getopt: <ulink 
      url="http://pear.php.net/package/Console_Getopt">http://pear.php.net/package/Console_Getopt</ulink>
     </para>
    </listitem>
   </itemizedlist>
   These packages are contained in the include tar.gz archive.
  </para>
 </sect1>
-->

 <sect1 id="dev.unit_test.writing"> 
  <title>Writing Tests</title>
  <para>Information about writing tests for &cartoweb; can be separated into
    two parts. First part about writing Unit tests in general, useful for
    people new to PhpUnit. Then a part more specific about the infrastructure 
    which is available in &cartoweb; for writing tests.</para>
  <sect2 id="dev.unit_test.writing.base"> 
  <title>General Information About Writing Tests</title>
  <para>
   Test cases are located in directory <filename>tests</filename> for testing
   the core of &cartoweb; and in the directories <filename>&lt;project&gt;/tests</filename>
   for for tests specific to project <filename>&lt;project&gt;</filename>.
   Inside these <filename>tests</filename> directories, path hierarchy mirrors
   the existing hierarchy they are testing. For instance, the <filename>tests</filename>
   hierarchy for the core &cartoweb; testing is the following:
   <screen><![CDATA[client
    CartoclientTest.php
    CartoserverServiceTest.php
    AllTests.php
common
    BasicTypesTest.php
    AllTests.php
coreplugins
    AllTests.php
    ...
plugins
    AllTests.php
    ...
]]></screen>

    For the <literal>test_main</literal> project, the hierarchy is the following:
   <screen><![CDATA[coreplugins
    AllTests.php
    ...
plugins
    AllTests.php
    ...
misc
    AllTests.php
    < misc tests >
    ...
...]]></screen>

  </para>
  <para>
   Each directory including tests root directory has a file named 
   <filename>AllTests.php</filename>.  This is called a test suite. 
   It is used to run all tests of a specific directory (ie "package").
  </para>
  <warning>
   <para>
   All test case and test suite classes must have the name 
   of their file relative path without extension, with '/'
   replaced by '_'. For instance, class 
   <constant>client_CartoclientTest</constant> file name must be 
   <filename>&lt;cartoweb3_root&gt;/tests/client/CartoclientTest.php</filename>.
   </para>
  </warning>
  <para>

  </para>
  <para>
  The following example shows a test in <filename>common/BasicTypeTest.php</filename> 
  file:
   <example id="dev.unit_test.writing.basic">
    <title>Simple test case (<filename>BasicTypesTests.php</filename>)</title>
    <programlisting><![CDATA[<?php
require_once 'PHPUnit2/Framework/TestCase.php';
require_once(CARTOWEB_HOME . 'common/basic_types.php');

class common_BasicTypesTest extends PHPUnit2_Framework_TestCase {

        public function testBboxFrom2Points() {

                $bbox = new Bbox();
                $point1 = new Point(12, 34);
                $point2 = new Point(56, 78);
                $bbox->SetFrom2Points($point1, $point2);

                $this->assertEquals(12, $bbox->minx);
                $this->assertEquals(34, $bbox->miny);
                $this->assertEquals(56, $bbox->maxx);
                $this->assertEquals(78, $bbox->maxy);
        }
}
?>]]></programlisting>
   </example>
  </para>
  <para>
   Each function with name starting with 'test' will be considered as
   a test case by the automated test runner. You may also want to use 
   functions <function>setUp()</function> and <function>tearDown()</function>
   to initialize and clean a test environment.
  </para>
  <para>
   Method <function>assertEquals</function> tests if two values have 
   the same values. If not, the test will be added to the final report as failure.
  </para>

  <para>
    As stated previously, all test classes have to belong to a test suite. The
    next example shows how such a test suite is built, by grouping all tests
    together in the <methodname>suite()</methodname> method.
  <example id="dev.unit_test.writing.all_test">
   <title>
    Test suite (<filename>AllTests.php</filename>) 
   </title>
   <programlisting><![CDATA[<?php

require_once 'PHPUnit2/Framework/TestSuite.php';
require_once 'CartoclientTest.php';
require_once 'CartoserverServiceTest.php';

class client_AllTests {

        public static function suite() {

                $suite = new PHPUnit2_Framework_TestSuite;

                $suite->addTestSuite('client_CartoclientTest');
                $suite->addTestSuite('client_CartoserverServiceTest');

                return $suite;
        }
}
?>
]]></programlisting>

  </example>
  </para>
  <para>
    All test suites are then grouped together into the root test suite. It is
    shown there for information.
  <example id="dev.unit_test.writing.root">
   <title>
    Root directory's AllTests.php:
   </title>
   <para>
    <programlisting><![CDATA[<?php

require_once 'PHPUnit2/Framework/TestSuite.php';
require_once 'client/AllTests.php';
require_once 'common/AllTests.php';

class AllTests {

        public static function suite() {

                $suite = new PHPUnit2_Framework_TestSuite;

                $suite->addTest(client_AllTests::suite());
                $suite->addTest(common_AllTests::suite());

                return $suite;
        }
}
?>]]></programlisting>
   </para>
  </example>
  </para>
  </sect2>
  <sect2 id="dev.unit_test.writing.framework"> 
    <title>Specific Information for Tests</title>
    <para>This section describes specific features developped in &cartoweb;
      for running tests, and infrastructure classes for more simple test 
      case writing.</para>
      <sect3 id="dev.unit_test.writing.framework.httpunit">
        <title>HttpUnit Based Tests</title>
        <para>
          To test features of the cartoclient, the 
            <ulink url="http://httpunit.sourceforge.net/">HttpUnit</ulink>
          software is used.
        It is written in Java, and there is no Php port. The http unit tests 
        are run if you have a JVM in you path.
        </para>
        <para>
        For more information about running HttpUnit tests, see the
         <filename>tests/client/httpunit/README</filename> file in 
         the &cartoweb; distribution.
        </para>
      </sect3>

      <sect3 id="dev.unit_test.writing.framework.plugins">
        <title>Testing &cartoweb; Plugins</title>
        <para>
          Plugins are a main component in &cartoweb; architecture. That's why
          there is support to maintain common code used for testing plugins.
          As described in <xref linkend="dev.unit_test.writing.base"/> the tests
          for plugins have to mirror the file hierarchy of the base application.
          That's why there are <filename>coreplugins</filename> and 
          <filename>plugins</filename> directories where test for core plugins 
          and plugins are stored respectively.
          <note><para>Tests are also available for projects. So, to test
            a plugin in a project, the path of the test will be 
              <filename>&lt;cartoweb3&gt;/&lt;projectname&gt;/tests/plugin/&lt;pluginname&gt;
                </filename></para>
          </note>
        </para>
        <para>
        Testing plugins is separated into two tasks:
        <orderedlist>
          <listitem>
            <para>Locally testing client, common or server classes. For 
              plugin client classes, it requires a &cartoclient; environment
              available, and identically a &cartoserver; environment 
              for testing server classes.</para>
          </listitem>
          <listitem>
            <para>
              Remote plugin tests, throught the webservice API. This kind of tests
              are related to the server plugins, that's why we chose to put them
              in the <filename>server</filename> folder of plugins.
            </para>
          </listitem>
        </orderedlist>
        </para>
        <para>
          For the first point mentionned above, general Unit tests rules apply, as
          described in <xref linkend="dev.unit_test.writing.base"/>.
        </para>
        <para>
          For the second point stated, a help class named 
            <classname>client_CartoserverServiceTest</classname> can be extended
            by the testing classes. In turn, <classname>client_CartoserverServiceTest</classname>
            extends other classes which offer additional helpful methods. For
            the complete list of available methods, please have a look at the 
            generate API docs (as more may be added in future). The main useful
            methods are <methodname>createRequest()</methodname> for initializing
            a new request, <methodname>getMap()</methodname> for lanching the 
            request.
        </para>
        <tip>
        <para>Having a look at an existing plugin test case is the best starting
          point for writing new tests.</para></tip>
      </sect3>      

      <sect3 id="dev.unit_test.writing.framework.projects">
        <title>Tests for projects</title>
        <para>
          Each &cartoweb; project can have its set of tests directly inside the project,
          in a directory <filename>tests</filename>. Inside this directory, you have to
          use the same hierarchy as in the main <filename>tests</filename> directory.
        </para>
        <para>
        Inside these <filename>tests</filename> directories, the same mechanism is used
        for testing as the main <filename>tests</filename> directory. The best way
        to get started is to have a look at the <literal>test_main</literal> project
        for a starting point.
        </para>
        <sect4 id="dev.unit_test.writing.framework.projects.invoking">
          <title>Invoking tests for a specific project</title>
          <para>
          For now, only the command line can be used for invoking tests for a specific project.
          An environment variable CARTOWEB_TEST_PROJECT can be used to define which test to launch.
          Under a Unix like shell enviroment, the command line to use is:
         <screen><![CDATA[CARTOWEB_TEST_PROJECT=<myproject> <php-bin> phpunit.php projects_AllTests projects/AllTests.php]]></screen>
          </para>
        </sect4>
      </sect3>
      
  </sect2>
 </sect1>

 <sect1 id="unit_test.running"> 
  <title>Running Tests</title>
  <para>
   Unit tests are runned using the command line interface (CLI).
   To run a test case or a test suite, type the following
   command in directory <filename>&lt;cartoweb3_root&gt;/tests</filename>:
   <screen><![CDATA[<php-bin> phpunit.php <test-class> <php-file>]]></screen>
   Where &lt;php-bin&gt; is the PHP binary, &lt;test-class&gt;
   is the name of the test class 
   (<literal>AllTests</literal>, <literal>client_AllTests</literal>, 
    <literal>client_CartoclientTest</literal>, etc.) and &lt;php-file&gt;
   is the name of the PHP file containing the test case 
   (<filename>client/CartoclientTest.php</filename>).
  </para>
  <para>
  Result should look like this:
   <screen><![CDATA[PHPUnit 2.0.3 by Sebastian Bergmann.

.......F.....

Time: 0.0410950183868
There was 1 failure:
1) testpointtobbox
expected same: <113> was not: <123>
/home/yves/cartoweb3-proto2/tests/common/BasicTypesTest.php:59
/home/yves/cartoweb3-proto2/tests/phpunit.php:24

FAILURES!!!
Tests run: 12, Failures: 1, Errors: 0, Incomplete Tests: 0.
Content-type: text/html
X-Powered-By: PHP/5.0.1]]></screen>
   In this case, 12 tests were run with one failure.
  </para>
 </sect1>

</chapter>
