.. _developer-testing:
Testing
=======
.. readingtime::
The tests tree mirrors the ``src/tephpy`` package layout: tests for top-level modules
live at the ``tests/`` root, and every subpackage has a matching directory —
``tests/plotting/`` for ``tephpy.plotting`` — however few modules it carries.
``tephpy.samples`` is a lone ``__init__.py`` and still has ``tests/samples/``.
``tests/test_layout.py`` holds the tree to that, so a subpackage arriving without its
directory fails a test rather than waiting to be noticed. Place a new test module at the
level of the module it exercises; the shared ``fixtures/`` and ``baseline/`` directories
stay at the root.
Running the Suite
-----------------
.. code:: console
$ pixi run tests
`pytest `__ runs with a strict configuration and ``filterwarnings = ["error"]``, so a warning
is a failure. ``pixi run tests-clean`` removes the artifacts a run leaves behind.
Image Comparison
----------------
Plotting tests compare a rendered figure against a recorded baseline with pytest-mpl,
marked ``@pytest.mark.mpl_image_compare``. Both CI and ``pixi run tests`` pass ``--mpl``,
so the comparison is enforced rather than skipped.
.. code:: console
$ pixi run baselines
regenerates ``tests/baseline``. Reach for it when a lockfile bump moves
`matplotlib `__ or `freetype `__, and re-verify across all three test environments afterwards — the baselines are
shared, and a regeneration that satisfies one Python can fail another.
.. tip::
A failed comparison is far easier to read as a report than as a diff of two
numbers. `pytest-mpl `__ writes one on
request:
.. code:: console
$ pixi run tests --mpl-generate-summary=html --mpl-results-path=mpl-results
The report puts the baseline, the render and their difference side by side for
every failure, which usually says at a glance whether a change is a real
regression or a font moving underneath it. ``json`` and ``basic-html`` are the
other supported forms.
No Test Touches the Network
---------------------------
The ingest readers are tested against recorded captures under ``tests/fixtures/io/``,
byte-faithful and with their provenance recorded beside them. Nothing in the suite makes a
request.
The reason is worth stating, because the rule costs something. A suite that reached the
University of Wyoming would fail on their outage rather than on a defect here, and a red
tick that means "somebody else is down" teaches a reader to ignore red ticks. What the rule
gives up is knowing when the archive moves under us — every gate stays green while
``tephpy.io.wyoming`` stops working. :doc:`ci` describes the scheduled job that pays that
cost instead.