Skip to content

Commit 7814ada

Browse files
timhoffmstory645
andauthored
DOC: Improve testing documentation (matplotlib#31584)
Rordered topics and made descriptions more concise. --------- Co-authored-by: hannah <story645@gmail.com>
1 parent fc97054 commit 7814ada

1 file changed

Lines changed: 83 additions & 34 deletions

File tree

doc/devel/testing.rst

Lines changed: 83 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 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 classes begin with ``"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+
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, such as
131+
``[1, 2, 3]``, ``range(5)`` or ``np.arange(5)``, because it
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 when an algorithmic way to generate the data is too
140+
cumbersome or impossible. 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,56 @@ 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 to create figures or to modify `.rcParams` to test some functionality.
153+
Cleanup of such side effects is handled automatically through a pytest fixture
154+
(``matplotlib.testing.conftest.mpl_test_settings``) so that no manual cleanup is
155+
necessary.
156+
157+
In particular, you don't need to call ``plt.close()``.
158+
159+
Testing with figures and Axes
160+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
161+
When you need figures and/or Axes, create them through the standard methods
162+
(``plt.figure()``, ``plt.subplots()``, etc.).
163+
164+
Creating figures and Axes is rather expensive (>100ms). Only create as many as you need for
165+
the test, and reuse them if possible. It is perfectly fine to test multiple parametrizations
166+
or related functionality in one test; i.e. extend the classical test structure
167+
*Arrange–Act–Assert* with multiple *Act-Assert* blocks, e.g. ::
168+
169+
def test_stackplot_facecolor():
170+
# Test that facecolors are properly passed and take precedence over colors parameter
171+
x = np.linspace(0, 10, 10)
172+
y1 = 1.0 * x
173+
y2 = 2.0 * x + 1
174+
175+
fig, ax = plt.subplots()
176+
177+
facecolors = ['r', 'b']
178+
179+
colls = ax.stackplot(x, y1, y2, facecolor=facecolors, colors=['c', 'm'])
180+
for coll, fcolor in zip(colls, facecolors):
181+
assert mcolors.same_color(coll.get_facecolor(), fcolor)
182+
183+
# Plural alias should also work
184+
colls = ax.stackplot(x, y1, y2, facecolors=facecolors, colors=['c', 'm'])
185+
for coll, fcolor in zip(colls, facecolors):
186+
assert mcolors.same_color(coll.get_facecolor(), fcolor)
187+
188+
Assert values rather than visual results when feasible. This is clearer,
189+
less computationally expensive and less fragile than comparing images, e.g. ::
190+
191+
def test_savefig_preserve_layout_engine():
192+
fig = plt.figure(layout='compressed')
193+
fig.savefig(io.BytesIO(), bbox_inches='tight')
194+
assert fig.get_layout_engine()._compress
195+
139196
.. _image-comparison:
140197

141-
Writing an image comparison test
142-
--------------------------------
198+
Testing with reference images
199+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
143200

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

183-
184-
Compare two methods of creating an image
185-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
240+
Testing by comparing two methods to create an image
241+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
186242

187243
Baseline images take a lot of space in the Matplotlib repository.
188244
An alternative approach for image comparison tests is to use the
@@ -228,13 +284,6 @@ See the documentation of `~matplotlib.testing.decorators.image_comparison` and
228284
`~matplotlib.testing.decorators.check_figures_equal` for additional information
229285
about their use.
230286

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-
238287
Using GitHub Actions for CI
239288
---------------------------
240289

0 commit comments

Comments
 (0)