1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
|
.. title:: Get Started
###########
Get Started
###########
This section describes how to configure simple image comparison testing with ``pytest-mpl``.
It assumes that you already have a `pytest <https://docs.pytest.org>`__ test suite set up for your project.
Install ``pytest-mpl``
^^^^^^^^^^^^^^^^^^^^^^
First, install ``pytest-mpl`` and also include it in your project's "test" dependencies:
.. code-block:: python
pip install pytest-mpl
Write image comparison tests
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Then, alongside your existing tests, write test functions that create a figure.
These image comparison tests must be decorated with ``@pytest.mark.mpl_image_compare`` and return the figure for testing:
.. code-block:: python
import matplotlib.pyplot as plt
import pytest
@pytest.mark.mpl_image_compare
def test_plot():
fig, ax = plt.subplots()
ax.plot([1, 2])
return fig
Generate baseline images
^^^^^^^^^^^^^^^^^^^^^^^^
Then, generate reference images by running the test suite with the ``--mpl-generate-path`` option:
.. code-block:: bash
pytest --mpl-generate-path=baseline
If, for example, you are using a directory structure like this:
.. code-block::
.
└── tests
├── plotting
│ └── test_plotting.py
└── utils
└── test_utils.py
Then, the generated images will be placed in a new directory called ``baseline`` located where you ran pytest:
.. code-block::
.
├── baseline
│ ├── test_plot.png
│ └── test_util.png
└── tests
├── plotting
│ └── test_plotting.py
└── utils
└── test_utils.py
Take a look at the generated images inside the new ``baseline`` directory.
If they are correct, move each baseline image to a sub-directory called ``baseline`` relative to the test files:
.. code-block::
.
└── tests
├── plotting
│ ├── baseline
│ │ └── test_plot.png
│ └── test_plotting.py
└── utils
├── baseline
│ └── test_util.png
└── test_utils.py
Then, commit these baseline images to your repository.
Run the image comparison tests
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You now have a set of baseline images that can be used to verify the figures generated by your code.
You can now run the test suite as usual.
To enable image comparison testing, pass ``--mpl``:
.. code-block:: bash
pytest --mpl
You should observe that the tests pass.
Try modifying the test function and run the test suite again.
The test should now fail, because the generated image does not match the reference image.
Try running the test suite without ``--mpl``.
Even through the figure has changed, the test will pass, because image comparison testing is disabled.
.. rubric:: Running pytest without pytest-mpl installed
If ``pytest-mpl`` is not installed, the image comparison tests will cause pytest to show a warning, ``PytestReturnNotNoneWarning``.
Installing pytest-mpl will solve this issue.
When ``pytest-mpl`` is installed but not enabled, it will intercept the returned figure and close it without doing any comparison.
Alternatively, the image comparison tests can be deselected by running pytest with ``-m "not mpl_image_compare"``.
Or the following can be included in your test functions to skip if ``pytest-mpl`` is not installed:
.. code-block:: python
@pytest.mark.mpl_image_compare
def test_plot():
pytest.importorskip("pytest_mpl")
...
.. rubric:: Tests can fail when Matplotlib and FreeType versions change
If the Matplotlib version changes, or if the FreeType version changes, the generated images may change.
This is mostly because the text rendering in Matplotlib is dependent on the FreeType version.
It is recommended to pin the Matplotlib and FreeType versions in your testing environments to avoid this issue.
There are also a number of :ref:`configuration options for controlling the sensitivity of the comparison <controlling-sensitivity>`.
Image comparison mode
^^^^^^^^^^^^^^^^^^^^^
The above example uses the image comparison mode, which is the default when just ``--mpl`` is set.
Pros and cons of this mode are:
- :octicon:`diff-added;1em;sd-text-success` Easy to configure
- :octicon:`diff-added;1em;sd-text-success` Easy to run the tests and see the results
- :octicon:`diff-removed;1em;sd-text-danger` Baseline images usually need to be checked into the repository with the tests (larger repo)
For a more detailed example of image comparison testing, see the :doc:`image comparison mode how-to guide <image_mode>`.
Also see the :doc:`configuration guide <configuration>` for more information on configuring image comparison testing.
Hash comparison mode
^^^^^^^^^^^^^^^^^^^^
Instead of comparing to baseline images, you can instead compare against a JSON library of SHA-256 hashes of the baseline image files.
Pros and cons of this mode are:
- :octicon:`diff-added;1em;sd-text-success` Easy to configure
- :octicon:`diff-removed;1em;sd-text-danger` Difficult to *see* how a failing test differs from the baseline
- :octicon:`diff-added;1em;sd-text-success` Baseline images do not need to be checked into the repository with the tests (smaller repo)
See the :doc:`hash comparison mode how-to guide <hash_mode>` for more information on how to use this mode.
Also see the :doc:`configuration guide <configuration>` for more information on configuring hash comparison testing.
.. _hybrid-usage:
Hybrid mode: hash, then image, comparison
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can also use a "hybrid mode", which uses both baseline images and hashes.
A figure is first *assessed* against the baseline hash.
If the hash does not match, the figure will then be *compared* to the baseline image.
This mode can also be configured to :ref:`always compare the figure to the baseline image <results-always>`, even if the hash matches.
In this mode, only the hash assessment will affect the success status of the test.
If the hash assessment fails, the test will fail, even if the image comparison passes.
This mode is intended for projects which have a large number of tests, and where it is impractical to store all of the baseline images in the repository.
These projects can use this mode to store the baseline images in a separate repository, and only store hashes in the main repository.
In PRs, contributors only need to update the hashes, and the CI tests will pass if the hashes match.
For the baseline image comparison, ``pytest-mpl`` will download the baseline image from a URL and compare it to the generated image.
Pros and cons of this mode are:
- :octicon:`diff-removed;1em;sd-text-danger` Usually more complex to configure (managing a separate baseline image repository)
- :octicon:`diff-added;1em;sd-text-success` Easy to run the tests and see the results
- :octicon:`diff-added;1em;sd-text-success` Baseline images can be stored in a separate repository (smaller main repo)
See the :doc:`hybrid mode how-to guide <hybrid_mode>` for more information on how to use this mode.
Also see the :doc:`configuration guide <configuration>` for more information on configuring hybrid comparison testing.
Test results
^^^^^^^^^^^^
By default, the expected, actual, and difference files are written to a temporary directory with a non-deterministic path.
You can :ref:`configure the results directory <results-path>` to save to a specific location::
pytest --mpl --mpl-results-path=results
The ``results`` directory will then contain one sub-directory per test, and each sub-directory will contain the files mentioned above.
If you are using a continuous integration (CI) service, you can upload this directory as an artifact.
HTML summary reports
--------------------
``pytest-mpl`` can also generate HTML reports of the image comparison results, allowing you to see the results of the image comparison tests in a web browser.
See the :ref:`configuration documentation <generate-summary>` for more information on how to generate the HTML report.
Some CI services, such as CircleCI, can host the HTML summary on a web server so it can be viewed directly in the browser.
On other CI services, such as GitHub Actions, you can download the artifact and open the local HTML file in a web browser.
+---------------+---------------+---------------+
| |html all| | |html filter| | |html result| |
+---------------+---------------+---------------+
Test failure example
--------------------
If the images produced by the tests are correct, then the test will pass.
If the images are not correct, the test will fail and a message similar to the following will be shown in the pytest logs::
E Exception: Error: Image files did not match.
E RMS Value: 142.2287807767823
E Expected:
E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/baseline-coords_overlay_auto_coord_meta.png
E Actual:
E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/coords_overlay_auto_coord_meta.png
E Difference:
E /var/folders/zy/t1l3sx310d3d6p0kyxqzlrnr0000gr/T/tmp4h4oxr7y/coords_overlay_auto_coord_meta-failed-diff.png
E Tolerance:
E 10
The image paths included in the exception are then available for inspection:
+----------------+----------------+-------------+
| Expected | Actual | Difference |
+================+================+=============+
| |expected| | |actual| | |diff| |
+----------------+----------------+-------------+
In this case, the differences are very clear, while in some cases it may be necessary to use the difference image, or blink the expected and actual images, in order to see what changed.
Continue reading
^^^^^^^^^^^^^^^^
See the :doc:`configuration guide <configuration>` for more information on configuring ``pytest-mpl``.
For examples of how to configure the different operating modes, see the following how-to guides:
* :doc:`image_mode`
* :doc:`hash_mode`
* :doc:`hybrid_mode`
.. |html all| image:: images/html_all.png
.. |html filter| image:: images/html_filter.png
.. |html result| image:: images/html_result.png
.. |expected| image:: images/baseline-coords_overlay_auto_coord_meta.png
.. |actual| image:: images/coords_overlay_auto_coord_meta.png
.. |diff| image:: images/coords_overlay_auto_coord_meta-failed-diff.png
|