Testing the plugin
Tests live under tests/, mirroring the source tree 1:1 — every module in
stratified_packager/ and scripts/ has a test_*.py at the same relative path.
Tests that need a running QGIS are marked @pytest.mark.qgis and guard their imports with
pytest.importorskip("qgis"), so they skip cleanly where QGIS is unavailable.
The test stack (pytest,
pytest-cov,
pytest-qgis,
pytest-qt,
hypothesis) is managed with uv and configured
under [tool.pytest] / [tool.coverage] in pyproject.toml.
Routine runs go through just (which shells out via uv run):
# all tests, with coverage (--cov is on by default)
just test
# a single module, or a single test
just test tests/stratified_packager/test___about__.py
just test tests/stratified_packager/test___about__.py::test_version_semver
# select by keyword
just test -k pattern
Coverage
Coverage is collected by default (--cov is configured under [tool.pytest] in
pyproject.toml) and an HTML report is written to htmlcov/. Browse it with:
just serve-cov [PORT] # serve htmlcov/ (default port 8080)
just browse-cov [PORT] # open http://localhost:PORT
Aim for ≥ 80% coverage overall and ≥ 90% on core plugin logic.
Full local gate
just check (alias just ci) runs the whole gate — all QA checks (just qa) followed by
the test suite. Run it before pushing.
PyQt5 / PyQt6
QGIS wraps whichever Qt binding the host ships — PyQt6 on QGIS 4.0+, PyQt5 on the 3.x LTRs —
behind qgis.PyQt. The CI matrix runs the suite on both (PyQt5: QGIS 3.40/3.44; PyQt6:
QGIS 4.0+), so a test that passes locally must pass under either binding.
Write tests against behaviour (return values, exceptions, side effects) through qgis.PyQt, not
against a specific binding’s import path or enum spelling. Let the callable resolve its own
try:/except ImportError: fallback; replicate that fallback in the test only when the divergence
can’t be hidden. When a behaviour exists only on the newer version, skip the test on older ones
with pytest.mark.skipif (see skip_if_no_unaccent in test_i18n.py) rather than forking the
assertion.
Running without QGIS
pytest-qgis and pytest-qt import qgis / PyQt6 at load time, so in an environment
without a QGIS/Qt runtime they must be disabled or they fail on autoload. Disable both and the
QGIS-marked modules skip via importorskip:
just test -p no:pytest_qgis -p no:pytest-qt
Leaving pytest-qgis enabled when QGIS is missing makes it error loudly on autoload — that is
intentional, so an absent or broken QGIS is never silently skipped.