summaryrefslogtreecommitdiff
path: root/docs/dev/testing.txt
diff options
context:
space:
mode:
Diffstat (limited to 'docs/dev/testing.txt')
-rw-r--r--docs/dev/testing.txt246
1 files changed, 246 insertions, 0 deletions
diff --git a/docs/dev/testing.txt b/docs/dev/testing.txt
new file mode 100644
index 000000000..bde54116f
--- /dev/null
+++ b/docs/dev/testing.txt
@@ -0,0 +1,246 @@
+===================
+ Docutils_ Testing
+===================
+
+:Author: Felix Wiemann
+:Author: David Goodger
+:Revision: $Revision$
+:Date: $Date$
+:Copyright: This document has been placed in the public domain.
+
+.. _Docutils: http://docutils.sourceforge.net/
+
+.. contents::
+
+When adding new functionality (or fixing bugs), be sure to add test
+cases to the test suite. Practise test-first programming; it's fun,
+it's addictive, and it works!
+
+This document describes how to run the Docutils test suite, how the
+tests are organized and how to add new tests or modify existing tests.
+
+
+Running the Test Suite
+======================
+
+Before checking in any changes, run the entire Docutils test suite to
+be sure that you haven't broken anything. From a shell::
+
+ cd docutils/test
+ ./alltests.py
+
+
+Python Versions
+===============
+
+The Docutils 0.4 release supports Python 2.1 [#py21]_ or later, with
+some features only working (and being tested) with Python 2.3+.
+Therefore, you should actually have Pythons 2.1 [#py21]_, 2.2, 2.3, as
+well as the latest Python installed and always run the tests on all of
+them. (A good way to do that is to always run the test suite through
+a short script that runs ``alltests.py`` under each version of
+Python.) If you can't afford intalling 3 or more Python versions, the
+edge cases (2.1 and 2.3) should cover most of it.
+
+.. [#py21] Python 2.1 may be used providing the compiler package is
+ installed. The compiler package can be found in the Tools/
+ directory of Python 2.1's source distribution.
+
+Good resources covering the differences between Python versions:
+
+* `What's New in Python 2.2`__
+* `What's New in Python 2.3`__
+* `What's New in Python 2.4`__
+* `PEP 290 - Code Migration and Modernization`__
+
+__ http://www.python.org/doc/2.2.3/whatsnew/whatsnew22.html
+__ http://www.python.org/doc/2.3.5/whatsnew/whatsnew23.html
+__ http://www.python.org/doc/2.4.1/whatsnew/whatsnew24.html
+__ http://www.python.org/peps/pep-0290.html
+
+.. _Python Check-in Policies: http://www.python.org/dev/tools.html
+.. _sandbox directory:
+ http://svn.berlios.de/viewcvs/docutils/trunk/sandbox/
+.. _nightly repository tarball:
+ http://svn.berlios.de/svndumps/docutils-repos.gz
+
+
+Unit Tests
+==========
+
+Unit tests test single functions or modules (i.e. whitebox testing).
+
+If you are implementing a new feature, be sure to write a test case
+covering its functionality. It happens very frequently that your
+implementation (or even only a part of it) doesn't work with an older
+(or even newer) Python version, and the only reliable way to detect
+those cases is using tests.
+
+Often, it's easier to write the test first and then implement the
+functionality required to make the test pass.
+
+
+Writing New Tests
+-----------------
+
+When writing new tests, it very often helps to see how a similar test
+is implemented. For example, the files in the
+``test_parsers/test_rst/`` directory all look very similar. So when
+adding a test, you don't have to reinvent the wheel.
+
+If there is no similar test, you can write a new test from scratch
+using Python's ``unittest`` module. For an example, please have a
+look at the following imaginary ``test_square.py``::
+
+ #! /usr/bin/env python
+
+ # Author: your name
+ # Contact: your email address
+ # Revision: $Revision$
+ # Date: $Date$
+ # Copyright: This module has been placed in the public domain.
+
+ """
+ Test module for docutils.square.
+ """
+
+ import unittest
+ import docutils.square
+
+
+ class SquareTest(unittest.TestCase):
+
+ def test_square(self):
+ self.assertEqual(docutils.square.square(0), 0)
+ self.assertEqual(docutils.square.square(5), 25)
+ self.assertEqual(docutils.square.square(7), 49)
+
+ def test_square_root(self):
+ self.assertEqual(docutils.square.sqrt(49), 7)
+ self.assertEqual(docutils.square.sqrt(0), 0)
+ self.assertRaises(docutils.square.SquareRootError,
+ docutils.square.sqrt, 20)
+
+
+ if __name__ == '__main__':
+ unittest.main()
+
+For more details on how to write tests, please refer to the
+documentation of the ``unittest`` module.
+
+
+.. _functional:
+
+Functional Tests
+================
+
+The directory ``test/functional/`` contains data for functional tests.
+
+Performing functional testing means testing the Docutils system as a
+whole (i.e. blackbox testing).
+
+
+Directory Structure
+-------------------
+
++ ``functional/`` The main data directory.
+
+ + ``input/`` The input files.
+
+ - ``some_test.txt``, for example.
+
+ + ``output/`` The actual output.
+
+ - ``some_test.html``, for example.
+
+ + ``expected/`` The expected output.
+
+ - ``some_test.html``, for example.
+
+ + ``tests/`` The config files for processing the input files.
+
+ - ``some_test.py``, for example.
+
+ - ``_default.py``, the `default configuration file`_.
+
+
+The Testing Process
+-------------------
+
+When running ``test_functional.py``, all config files in
+``functional/tests/`` are processed. (Config files whose names begin
+with an underscore are ignored.) The current working directory is
+always Docutils' main test directory (``test/``).
+
+For example, ``functional/tests/some_test.py`` could read like this::
+
+ # Source and destination file names.
+ test_source = "some_test.txt"
+ test_destination = "some_test.html"
+
+ # Keyword parameters passed to publish_file.
+ reader_name = "standalone"
+ parser_name = "rst"
+ writer_name = "html"
+ settings_overrides['output-encoding'] = 'utf-8'
+ # Relative to main ``test/`` directory.
+ settings_overrides['stylesheet_path'] = '../docutils/writers/html4css1/html4css1.css'
+
+The two variables ``test_source`` and ``test_destination`` contain the
+input file name (relative to ``functional/input/``) and the output
+file name (relative to ``functional/output/`` and
+``functional/expected/``). Note that the file names can be chosen
+arbitrarily. However, the file names in ``functional/output/`` *must*
+match the file names in ``functional/expected/``.
+
+If defined, ``_test_more`` must be a function with the following
+signature::
+
+ def _test_more(expected_dir, output_dir, test_case, parameters):
+
+This function is called from the test case to perform tests beyond the
+simple comparison of expected and actual output files.
+
+``test_source`` and ``test_destination`` are removed from the
+namespace, as are all variables whose names begin with an underscore
+("_"). The remaining names are passed as keyword arguments to
+``docutils.core.publish_file``, so you can set reader, parser, writer
+and anything else you want to configure. Note that
+``settings_overrides`` is already initialized as a dictionary *before*
+the execution of the config file.
+
+
+Creating New Tests
+------------------
+
+In order to create a new test, put the input test file into
+``functional/input/``. Then create a config file in
+``functional/tests/`` which sets at least input and output file names,
+reader, parser and writer.
+
+Now run ``test_functional.py``. The test will fail, of course,
+because you do not have an expected output yet. However, an output
+file will have been generated in ``functional/output/``. Check this
+output file for validity and correctness. Then copy the file to
+``functional/expected/``.
+
+If you rerun ``test_functional.py`` now, it should pass.
+
+If you run ``test_functional.py`` later and the actual output doesn't
+match the expected output anymore, the test will fail.
+
+If this is the case and you made an intentional change, check the
+actual output for validity and correctness, copy it to
+``functional/expected/`` (overwriting the old expected output), and
+commit the change.
+
+
+.. _default configuration file:
+
+The Default Configuration File
+------------------------------
+
+The file ``functional/tests/_default.py`` contains default settings.
+It is executed just before the actual configuration files, which has
+the same effect as if the contents of ``_default.py`` were prepended
+to every configuration file.