Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit df3518f

Browse files
committed
docs: describe how to write tests
svn path=/trunk/matplotlib/; revision=7654
1 parent 13eae44 commit df3518f

2 files changed

Lines changed: 129 additions & 3 deletions

File tree

doc/devel/coding_guide.rst

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,8 +561,7 @@ external backend via the ``module`` directive. if
561561

562562

563563

564-
.. _license-discussion:
565-
564+
.. _sample-data:
566565

567566
Writing examples
568567
================
@@ -602,6 +601,9 @@ object::
602601
print 'datafile', datafile
603602

604603

604+
.. _license-discussion:
605+
606+
605607
Licenses
606608
========
607609

@@ -669,4 +671,113 @@ The other reason is licensing compatibility with the other python
669671
extensions for scientific computing: ipython, numpy, scipy, the
670672
enthought tool suite and python itself are all distributed under BSD
671673
compatible licenses.
672-
>
674+
675+
Testing
676+
=======
677+
678+
Matplotlib has a testing infrastructure based on nose_, making it easy
679+
to write new tests. The tests are in :mod:`matplotlib.tests`, and
680+
customizations to the nose testing infrastructure are in
681+
:mod:`matplotlib.testing`. (There is other old testing cruft around,
682+
please ignore it while we consolidate our testing to these locations.)
683+
684+
.. _nose: http://somethingaboutorange.com/mrl/projects/nose/
685+
686+
687+
Writing a simple test
688+
---------------------
689+
690+
Many elements of Matplotlib can be tested using standard tests. For
691+
example, here is a test from :mod:`matplotlib.tests.test_basic`::
692+
693+
from nose.tools import assert_equal
694+
695+
def test_simple():
696+
'''very simple example test'''
697+
assert_equal(1+1,2)
698+
699+
Nose determines which functions are tests by searching for functions
700+
beginning with "test" in their name.
701+
702+
Writing an image comparison test
703+
--------------------------------
704+
705+
Writing an image based test is only slightly more difficult than a
706+
simple test. The main consideration is that you must specify the
707+
"baseline", or expected, images in the
708+
:func:`~matplotlib.testing.decorators.image_comparison` decorator. For
709+
example, this test generates a single image and automatically tests
710+
it::
711+
712+
import numpy as np
713+
import matplotlib
714+
matplotlib.use('Agg')
715+
from matplotlib.testing.decorators import image_comparison
716+
import matplotlib.pyplot as plt
717+
718+
@image_comparison(baseline_images=['spines_axes_positions.png'])
719+
def test_spines_axes_positions():
720+
# SF bug 2852168
721+
fig = plt.figure()
722+
x = np.linspace(0,2*np.pi,100)
723+
y = 2*np.sin(x)
724+
ax = fig.add_subplot(1,1,1)
725+
ax.set_title('centered spines')
726+
ax.plot(x,y)
727+
ax.spines['right'].set_position(('axes',0.1))
728+
ax.yaxis.set_ticks_position('right')
729+
ax.spines['top'].set_position(('axes',0.25))
730+
ax.xaxis.set_ticks_position('top')
731+
ax.spines['left'].set_color('none')
732+
ax.spines['bottom'].set_color('none')
733+
fig.savefig('spines_axes_positions.png')
734+
735+
The mechanism for comparing images is extremely simple -- it compares
736+
an image saved in the current directory with one from the Matplotlib
737+
sample_data repository. The correspondence is done by matching
738+
filenames, so ensure that:
739+
740+
* The filename given to :meth:`~matplotlib.figure.Figure.savefig` is
741+
exactly the same as the filename given to
742+
:func:`~matplotlib.testing.decorators.image_comparison` in the
743+
``baseline_images`` argument.
744+
745+
* The correct image gets added to the sample_data respository with
746+
the name ``test_baseline_<IMAGE_FILENAME.png>``. (See
747+
:ref:`sample-data` above for a description of how to add files to
748+
the sample_data repository.)
749+
750+
751+
Known failing tests
752+
-------------------
753+
754+
If you're writing a test, you may mark it as a known failing test with
755+
the :func:`~matplotlib.testing.decorators.knownfailureif`
756+
decorator. This allows the test to be added to the test suite and run
757+
on the buildbots without causing undue alarm. For example, although
758+
the following test will fail, it is an expected failure::
759+
760+
from nose.tools import assert_equal
761+
from matplotlib.testing.decorators import knownfailureif
762+
763+
@knownfailureif(True)
764+
def test_simple_fail():
765+
'''very simple example test that should fail'''
766+
assert_equal(1+1,3)
767+
768+
Note that the first argument to the
769+
:func:`~matplotlib.testing.decorators.knownfailureif` decorator is a
770+
fail condition, which can be a value such as True, False, or
771+
'indeterminate', or may be a dynamically evaluated expression.
772+
773+
Creating a new module in matplotlib.tests
774+
-----------------------------------------
775+
776+
Let's say you've added a new module named
777+
``matplotlib.tests.test_whizbang_features``. For the buildbot slave
778+
machines to know to run a test, nose must look in that module. To add
779+
a module to the list searched, add the line::
780+
781+
args.append('matplotlib.tests.test_whizbang_features')
782+
783+
into :file:`test/run-mpl-test.py`.

lib/matplotlib/testing/decorators.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
from matplotlib.testing.compare import compare_images
77

88
def knownfailureif(fail_condition, msg=None):
9+
"""
10+
11+
Assume a will fail if *fail_condition* is True. *fail_condition*
12+
may also be False or the string 'indeterminate'.
13+
14+
*msg* is the error message displayed for the test.
15+
16+
"""
917
# based on numpy.testing.dec.knownfailureif
1018
if msg is None:
1119
msg = 'Test known to fail'
@@ -29,6 +37,13 @@ def failer(*args, **kwargs):
2937
return known_fail_decorator
3038

3139
def image_comparison(baseline_images=None, tol=1e-3):
40+
"""
41+
compare images generated by the test with those specified in
42+
*baseline_images*, which must correspond within tolerance *tol*,
43+
else an ImageComparisonFailure exception will be raised.
44+
45+
"""
46+
3247
if baseline_images is None:
3348
raise ValueError('baseline_images must be specified')
3449
def compare_images_decorator(func):

0 commit comments

Comments
 (0)