Skip to content

Commit efb3382

Browse files
committed
DOC: Improve testing documentation
Rordered topics and made descriptions more concise.
1 parent 05b9179 commit efb3382

1 file changed

Lines changed: 79 additions & 34 deletions

File tree

doc/devel/testing.rst

Lines changed: 79 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -100,34 +100,45 @@ to the folder where the baseline test images are stored. The triage tool require
100100
:ref:`QT <backend_dependencies>` is installed.
101101

102102

103-
Writing a simple test
104-
---------------------
103+
Writing tests
104+
-------------
105+
Tests are located in :file:`lib/matplotlib/tests`. They are organized to mirror
106+
the structure of the main code in :file:`lib/matplotlib`. For example, tests for
107+
the ``mathtext.py`` module are in :file:`lib/matplotlib/tests/test_mathtext.py`.
105108

106-
Many elements of Matplotlib can be tested using standard tests. For
107-
example, here is a test from :file:`matplotlib/tests/test_basic.py`::
109+
Naming follows standard pytest conventions:
108110

109-
def test_simple():
110-
"""
111-
very simple example test
112-
"""
113-
assert 1 + 1 == 2
111+
- files begin with ``"test_"``
112+
- test functions begin with ``"test_"``
113+
- test class begin ``"Test"``.
114114

115-
Pytest determines which functions are tests by searching for files whose names
116-
begin with ``"test_"`` and then within those files for functions beginning with
117-
``"test"`` or classes beginning with ``"Test"``.
115+
We prefer simple test functions, but test classes are also acceptable.
116+
Test function names should be descriptive of what they are testing, and long names
117+
like ``test_to_rgba_array_accepts_color_alpha_tuple_with_multiple_colors()`` are
118+
perfectly fine.
118119

119-
Some tests have internal side effects that need to be cleaned up after their
120-
execution (such as created figures or modified `.rcParams`). The pytest fixture
121-
``matplotlib.testing.conftest.mpl_test_settings`` will automatically clean
122-
these up; there is no need to do anything further.
120+
Simple unit tests
121+
^^^^^^^^^^^^^^^^^
123122

124-
Random data in tests
125-
--------------------
123+
Many elements of Matplotlib can be tested using simple unit tests, e.g. ::
126124

127-
Random data is a very convenient way to generate data for examples,
128-
however the randomness is problematic for testing (as the tests
129-
must be deterministic!). To work around this set the seed in each test.
130-
For numpy's default random number generator use::
125+
def test_to_rgba_explicit_alpha_overrides_tuple_alpha():
126+
assert mcolors.to_rgba(('red', 0.1), alpha=0.9) == (1, 0, 0, 0.9)
127+
128+
Data in tests
129+
^^^^^^^^^^^^^
130+
Try to use minimal explicit data. Often you can use explicit values like
131+
``[1, 2, 3]``, ``range(5)`` or ``np.arange(5)``. This is cheap and
132+
makes the test more readable.
133+
134+
When you need more and non-trivial data, generate it programmatically, e.g. ::
135+
136+
x = np.linspace(0, 2*np.pi, 101)
137+
y = 2 * np.sin(x) + 1
138+
139+
Use random numbers only, if an algorihmical way to generate the data is not
140+
possible or too cumbersome. In this case, set the seed to a fixed value to make
141+
the test deterministic. For numpy's default random number generator use ::
131142

132143
import numpy as np
133144
rng = np.random.default_rng(19680801)
@@ -136,10 +147,52 @@ and then use ``rng`` when generating the random numbers.
136147

137148
The seed is :ref:`John Hunter's <project_history>` birthday.
138149

150+
Test cleanup
151+
^^^^^^^^^^^^
152+
We often need figures or modify `.rcParams` to test some functionality. Cleanup
153+
of such side effects is handled automatically through the the pytest fixture
154+
``matplotlib.testing.conftest.mpl_test_settings``.
155+
156+
In particular, you don't need to call ``plt.close()``.
157+
158+
Testing with figures and Axes
159+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
160+
When you need figures and/or Axes, create them through the standard methods
161+
(``plt.figure()``, ``plt.subplots()``, etc.).
162+
163+
Creating figures and Axes is rather expensive (>100ms). Only create as many as you need for
164+
the test, and reuse them if possible. It is perfectly fine to do multiple operations
165+
and asserts in one test, e.g.::
166+
167+
def test_stackplot_facecolor():
168+
# Test that facecolors are properly passed and take precedence over colors parameter
169+
x = np.linspace(0, 10, 10)
170+
y1 = 1.0 * x
171+
y2 = 2.0 * x + 1
172+
173+
fig, ax = plt.subplots()
174+
175+
colls = ax.stackplot(x, y1, y2, facecolor=['r', 'b'], colors=['c', 'm'])
176+
for coll, fcolor in zip(colls, facecolors):
177+
assert mcolors.same_color(coll.get_facecolor(), fcolor)
178+
179+
# Plural alias should also work
180+
colls = ax.stackplot(x, y1, y2, facecolors=['r', 'b'], colors=['c', 'm'])
181+
for coll, fcolor in zip(colls, facecolors):
182+
assert mcolors.same_color(coll.get_facecolor(), fcolor)
183+
184+
Assert values rather than visual results when feasible. This is clearer,
185+
less expensive and less fragile than comparing images, e.g. ::
186+
187+
def test_savefig_preserve_layout_engine():
188+
fig = plt.figure(layout='compressed')
189+
fig.savefig(io.BytesIO(), bbox_inches='tight')
190+
assert fig.get_layout_engine()._compress
191+
139192
.. _image-comparison:
140193

141-
Writing an image comparison test
142-
--------------------------------
194+
Testing with reference images
195+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
143196

144197
Writing an image-based test is only slightly more difficult than a simple
145198
test. The main consideration is that you must specify the "baseline", or
@@ -180,9 +233,8 @@ texts (labels, tick labels, etc) are not really part of what is tested, use the
180233
will lead to smaller figures and reduce possible issues with font mismatch on
181234
different platforms.
182235

183-
184-
Compare two methods of creating an image
185-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
236+
Testing by comparing two methods to create an image
237+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
186238

187239
Baseline images take a lot of space in the Matplotlib repository.
188240
An alternative approach for image comparison tests is to use the
@@ -228,13 +280,6 @@ See the documentation of `~matplotlib.testing.decorators.image_comparison` and
228280
`~matplotlib.testing.decorators.check_figures_equal` for additional information
229281
about their use.
230282

231-
Creating a new module in matplotlib.tests
232-
-----------------------------------------
233-
234-
We try to keep the tests categorized by the primary module they are
235-
testing. For example, the tests related to the ``mathtext.py`` module
236-
are in ``test_mathtext.py``.
237-
238283
Using GitHub Actions for CI
239284
---------------------------
240285

0 commit comments

Comments
 (0)