1 .. include:: ../header.txt
7 :Authors: Lea Wiemann <LeWiemann@gmail.com>;
8 David Goodger <goodger@python.org>;
9 Docutils developers <docutils-developers@lists.sourceforge.net>
12 :Copyright: This document has been placed in the public domain.
14 :Abstract: This document describes how to run the Docutils test suite,
15 how the tests are organized and how to add new tests or modify
18 .. _Docutils: https://docutils.sourceforge.io/
22 When adding new functionality (or fixing bugs), be sure to add test
23 cases to the test suite. Practise test-first programming; it's fun,
24 it's addictive, and it works!
27 Running the Test Suite
28 ======================
30 Before checking in any changes, run the entire Docutils test suite to
31 be sure that you haven't broken anything. From a shell do::
36 Before `checking in`__ changes to the Docutils core, run the tests on
37 all `supported Python versions`_ (see below for details).
38 In a pinch, the edge cases should cover most of it.
41 The ``alltests.py`` test runner is based on the standard library's unittest_
43 Since Docutils 0.19, running ``python -m unittest`` and the pytest_
44 framework no longer result in spurious failures (cf. `bug #270`_).
45 However, there are differences in the reported number of tests
46 (``alltests.py`` also counts sub-tests).
47 In future, running the test suite may require pytest_.
49 __ policies.html#check-ins
50 .. _unittest: https://docs.python.org/3/library/unittest.html
51 .. _pytest: https://pypi.org/project/pytest
52 .. _`bug #270`: https://sourceforge.net/p/docutils/bugs/270/
57 Testing across multiple Python versions
58 ---------------------------------------
60 A Docutils release has a commitment to support a minimum Python version
61 and beyond (see dependencies__ in README.txt). Before a release is cut,
62 tests must pass in all `supported versions`_. [#]_
64 __ ../../README.html#dependencies
66 You can use `tox`_ to test with all supported versions in one go.
72 To test a specific version, use the ``pyNN`` environment. For example::
76 `pyenv`_ can be installed and configured (see `installing pyenv`_) to
77 get multiple Python versions::
79 # assuming your system runs 3.9.x
83 pyenv global system 3.7.12 3.8.12 3.10.1 3.11.0
86 rm -rf ~/.pyenv/shims && pyenv rehash
88 This will give you ``python3.7`` through ``python3.11``.
91 python3.7 -u alltests.py
93 python3.11 -u alltests.py
96 When using the `Python launcher for Windows`__, specify the Python version
97 as option, e.g., ``py -3.9 -u alltests.py`` for Python 3.9.
99 .. cf. https://sourceforge.net/p/docutils/bugs/434/
100 __ https://docs.python.org/3/using/windows.html#python-launcher-for-windows
103 .. [#] Good resources covering the differences between Python versions
104 are the `What's New` documents (`What's New in Python 3.11`__ and
107 __ https://docs.python.org/3/whatsnew/3.11.html
110 .. _supported versions:
111 .. _supported Python versions: ../../README.html#requirements
112 .. _pyenv: https://github.com/yyuu/pyenv
113 .. _installing pyenv: https://github.com/yyuu/pyenv#installation
114 .. _tox: https://pypi.org/project/tox/
120 Unit tests test single functions or modules (i.e. whitebox testing).
122 If you are implementing a new feature, be sure to write a test case
123 covering its functionality. It happens very frequently that your
124 implementation (or even only a part of it) doesn't work with an older
125 (or even newer) Python version, and the only reliable way to detect
126 those cases is using tests.
128 Often, it's easier to write the test first and then implement the
129 functionality required to make the test pass.
135 When writing new tests, it very often helps to see how a similar test
136 is implemented. For example, the files in the
137 ``test_parsers/test_rst/`` directory all look very similar. So when
138 adding a test, you don't have to reinvent the wheel.
140 If there is no similar test, you can write a new test from scratch
141 using Python's ``unittest`` module. For an example, please have a
142 look at the following imaginary ``test_square.py``::
144 #! /usr/bin/env python3
147 # Author: Your Name <your_email_address@example.org>
148 # Copyright: This module has been placed in the public domain.
151 Test module for docutils.square.
155 if __name__ == '__main__':
156 # prepend the "docutils root" to the Python library path
157 # so we import the local `docutils` package.
158 sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
160 import docutils.square
163 class SquareTest(unittest.TestCase):
165 def test_square(self):
166 self.assertEqual(docutils.square.square(0), 0)
167 self.assertEqual(docutils.square.square(5), 25)
168 self.assertEqual(docutils.square.square(7), 49)
170 def test_square_root(self):
171 self.assertEqual(docutils.square.sqrt(49), 7)
172 self.assertEqual(docutils.square.sqrt(0), 0)
173 self.assertRaises(docutils.square.SquareRootError,
174 docutils.square.sqrt, 20)
177 if __name__ == '__main__':
180 For more details on how to write tests, please refer to the
181 documentation of the ``unittest`` module.
185 Unit tests and functional test should generally disable configuration
186 files, setting the `_disable_config`__ setting to True ::
188 settings_overrides['_disable_config'] = True
190 in order to be independent on the users local configuration.
192 __ ../user/config.html#disable-config
199 The directory ``test/functional/`` contains data for functional tests.
201 Performing functional testing means testing the Docutils system as a
202 whole (i.e. blackbox testing).
208 + ``functional/`` The main data directory.
210 + ``input/`` The input files.
212 - ``some_test.txt``, for example.
214 + ``output/`` The actual output.
216 - ``some_test.html``, for example.
218 + ``expected/`` The expected output.
220 - ``some_test.html``, for example.
222 + ``tests/`` The config files for processing the input files.
224 - ``some_test.py``, for example.
230 When running ``test_functional.py``, all config files in
231 ``functional/tests/`` are processed. (Config files whose names begin
232 with an underscore are ignored.) The current working directory is
233 always Docutils' main test directory (``test/``).
235 For example, ``functional/tests/some_test.py`` could read like this::
237 # Source and destination file names.
238 test_source = "some_test.txt"
239 test_destination = "some_test.html"
241 # Keyword parameters passed to publish_file.
242 reader_name = "standalone"
245 settings_overrides['output-encoding'] = 'utf-8'
246 # Relative to main ``test/`` directory.
247 settings_overrides['stylesheet_path'] = '../docutils/writers/html4css1/html4css1.css'
249 The two variables ``test_source`` and ``test_destination`` contain the
250 input file name (relative to ``functional/input/``) and the output
251 file name (relative to ``functional/output/`` and
252 ``functional/expected/``). Note that the file names can be chosen
253 arbitrarily. However, the file names in ``functional/output/`` *must*
254 match the file names in ``functional/expected/``.
256 ``test_source`` and ``test_destination`` are removed from the
257 namespace, as are all variables whose names begin with an underscore
258 ("_"). The remaining names are passed as keyword arguments to
259 ``docutils.core.publish_file``, so you can set reader, parser, writer
260 and anything else you want to configure. Note that
261 ``settings_overrides`` is already initialized as a dictionary *before*
262 the execution of the config file.
268 In order to create a new test, put the input test file into
269 ``functional/input/``. Then create a config file in
270 ``functional/tests/`` which sets at least input and output file names,
271 reader, parser and writer.
273 Now run ``test_functional.py``. The test will fail, of course,
274 because you do not have an expected output yet. However, an output
275 file will have been generated in ``functional/output/``. Check this
276 output file for validity [#]_ and correctness. Then copy the file to
277 ``functional/expected/``.
279 If you rerun ``test_functional.py`` now, it should pass.
281 If you run ``test_functional.py`` later and the actual output doesn't
282 match the expected output anymore, the test will fail.
284 If this is the case and you made an intentional change, check the
285 actual output for validity and correctness, copy it to
286 ``functional/expected/`` (overwriting the old expected output), and
289 .. [#] `Docutils XML` can be validated with
290 ``xmllint --dtdvalid docs/ref/docutils.dtd --noout *.xml``.