Testing Guide — How to Run Tests¶
Overview¶
The Hera test infrastructure uses native Pytest with a Project-based data access pattern.
All tests live under hera/tests/ and can be executed with a single pytest command (or make test).
For the toolkit tests, data is loaded once per session into a shared Hera Project via test_repository.json,
and each toolkit test module receives a real toolkit instance backed by MongoDB —
no monkey-patching of getConfig / getDataSourceData is needed.
Key Principle
Toolkit tests do NOT know where files are stored on disk. They interact only with the Project and Toolkit APIs, exactly as production code does.
Architecture¶
hera/ # repository root
├── pytest.ini # Pytest configuration (testpaths = hera/tests)
├── Makefile # test, test-setup, test-notebooks, test-ui, test-all
├── scripts/s3/bootstrap_unittest_data.sh # Downloads the test data repository from S3
├── hera/
│ ├── utils/data/toolkit.py # dataToolkit (repository loader + direct-load helpers)
│ └── tests/
│ ├── conftest.py # Session-scoped project, per-toolkit fixtures, cleanup, helpers
│ ├── test_datalayer.py # Project / collections / datahandlers (MongoDB)
│ ├── test_repository.py # Repository add/get/load, path resolution
│ ├── test_repository_export.py # Project documents -> repository JSON export
│ ├── test_topography.py # TopographyToolkit tests
│ ├── test_landcover.py # LandCoverToolkit tests
│ ├── test_demography.py # DemographyToolkit (analysis + presentation)
│ ├── test_lowfreq.py # lowFreqToolKit + analysis + presentation
│ ├── test_highfreq.py # HighFreqToolKit + calculators + turbulence
│ ├── test_experiment.py # experiment toolkit (experimentHome)
│ ├── test_*.py # further modules, see "Other test modules" below
│ ├── unit/ # Small DB-free regression tests
│ ├── dynamic_loading/ # Dummy experiment + dummy toolkit fixtures data
│ ├── dynamic_loading_tests_pack/ # Dynamic toolkit/experiment loading tests (own conftest.py)
│ └── repository/testCases/ # Test JSON data for test_repository.py
└── ~/hera_unittest_data/ # External test data repository ($TEST_HERA)
├── data_config.json # Data configuration metadata (default_result_set, ...)
├── test_repository.json # Hera-format repository mapping all test data
├── measurements/ # Raw test data files
│ ├── GIS/raster/ # HGT, TIF files
│ ├── GIS/vector/ # SHP files
│ └── meteorology/ # Parquet files (lowfreqdata/, highfreqdata/)
└── expected/ # Expected output result sets
└── BASELINE/
Data Flow¶
sequenceDiagram
participant Session as conftest.py
participant DT as dataToolkit
participant Project as Project
participant DB as MongoDB
participant Fixtures as Fixtures
participant Tests as Tests
Session->>Session: Read TEST_HERA env var
Session->>Session: Open test_repository.json
Session->>Project: Project(PYTEST_HERA_PROJECT, filesDirectory=tmp)
Session->>DT: loadAllDatasourcesInRepositoryJSONToProject()
loop Each toolkit in JSON
DT->>DB: setConfig + addDataSource
end
Session->>Fixtures: Create toolkit fixtures
Note over Fixtures: topo, lc, demo,<br/>lf, hf toolkits
Fixtures->>Tests: Provide instances
Tests->>DB: getDataSourceData()
Tests->>Tests: analysis + presentation
Session->>DB: Teardown: purge every document of the project
Prerequisites¶
1. Python Environment¶
The test dependencies (pytest, nbclient, nbformat, ipykernel) are pinned in requirements.txt,
so the standard Hera environment is enough:
make install-env # creates ~/.pyhera/environment and installs requirements.txt + hera (editable)
source activate_hera.sh # activates it and puts the repository on PYTHONPATH
See Installation & Setup for the full procedure. CI runs the suite on Python 3.11.
Some modules need packages that are not pip-installable and are only importable when their clone is on PYTHONPATH:
hermes(KaplanOpenSource/hermes) —test_hermes_workflow.py,test_of_lsm_flow.py, part oftest_workflow_execution.pyargos(KaplanOpenSource/pyargos) — parts oftest_experiment.pyand the dynamic-loading pack
These tests skip (pytest.importorskip / skipif) when the package is missing.
2. Test Data Repository¶
The toolkit tests rely on external data files stored in $TEST_HERA (default ~/hera_unittest_data/).
This directory must contain:
data_config.json— metadata about paths, assets, and result sets (default_result_set)test_repository.json— Hera-format repository mapping all test datasources to their toolkitsmeasurements/— raw data files (HGT, TIF, SHP, Parquet, etc.)expected/— expected output files organized by result set
make test downloads it automatically when $TEST_HERA/test_repository.json does not exist, by running:
./scripts/s3/bootstrap_unittest_data.sh --target-dir ~/hera_unittest_data
# optional: --base-url URL (default https://s3.eu-west-1.amazonaws.com/hera.kaplanopensource.co.il)
The script reads latest.json and manifest.json from the public bucket, downloads every listed file and
verifies its SHA-256.
The published snapshot is a subset
At the time of writing, the snapshot in the bucket (poc-manual-20260413-v1) contains only
data_config.json, test_repository.json, one HGT tile (N31E034.hgt), YAVNEEL.parquet and an empty
expected/BASELINE/. Tests whose data file is missing skip themselves, so with this snapshot the
landcover, demography and highfreq tests, and some topography tests, are skipped (locally and in CI).
make test-setup only creates an empty skeleton (measurements/..., expected/BASELINE/, a minimal
data_config.json and {} as test_repository.json). Because test_repository.json then exists,
make test will no longer bootstrap from S3 — delete the skeleton first if you want the download.
3. MongoDB¶
The toolkit, datalayer and repository tests require a running MongoDB instance reachable through
~/.pyhera/config.json (see MongoDB setup).
Locally, make mongo-up starts a mongo:5.0 container on 127.0.0.1:27017.
The session-scoped project fixture loads data into MongoDB at startup and purges it on teardown.
test_datalayer.py and test_experiment.py probe MongoDB at import time and skip their DB tests when it is unreachable.
4. Environment Variables¶
| Variable | Required | Default | Description |
|---|---|---|---|
TEST_HERA |
No (but see note) | ~/hera_unittest_data |
Path to the test data repository root |
RESULT_SET |
No | default_result_set from data_config.json, else BASELINE |
Name of the expected-output result set |
GDF_TOL_AREA |
No | 1e-7 |
Area tolerance for geometry comparison in compare_dataframes |
MPLBACKEND |
No | (system default) | Set to Agg for headless runs (CI does) |
PREPARE_EXPECTED_OUTPUT |
— | — | Not implemented in master. It is mentioned in the conftest.py docstring, but no code reads it |
TEST_HERA and the landcover tests
conftest.py falls back to ~/hera_unittest_data when TEST_HERA is unset, but test_landcover.py
builds its data path from TEST_HERA alone and skips the whole module when the variable is unset.
Export TEST_HERA explicitly (make test does this for you).
See also: Environment Variables Reference
How to Run Tests¶
Run All Tests¶
This bootstraps the test data if needed and then runs
PYTHONPATH=. TEST_HERA=$(TEST_HERA) pytest hera/tests/ -v -m "not notebook".
TEST_HERA can be overridden: make test TEST_HERA=/data/hera_unittest_data.
Equivalent manual invocation:
source activate_hera.sh
export TEST_HERA=~/hera_unittest_data
pytest hera/tests/ -v -m "not notebook"
Note
Running plain pytest hera/tests/ without -m "not notebook" also executes test_notebooks.py,
which runs every notebook in the repository and is slow.
Other Make Targets¶
| Target | What it runs |
|---|---|
make test-setup |
Creates the empty test data skeleton at $(TEST_HERA) |
make test-notebooks |
pytest hera/tests/test_notebooks.py -v (every *.ipynb in the repo, in a fresh kernel) |
make test-ui |
npm install && npm run test:all in ui/client/ |
make test-all |
test, then test-notebooks, then test-ui |
Run a Specific Test Module¶
pytest hera/tests/test_datalayer.py -v
pytest hera/tests/test_repository.py -v
pytest hera/tests/test_topography.py -v
pytest hera/tests/test_landcover.py -v
pytest hera/tests/test_lowfreq.py -v
pytest hera/tests/test_highfreq.py -v
pytest hera/tests/test_demography.py -v
Run a Specific Test Class or Function¶
# Run all tests in a class
pytest hera/tests/test_topography.py::TestGetPointElevation -v
# Run a single test
pytest hera/tests/test_topography.py::TestGetPointElevation::test_basic -v
Select by Marker¶
The markers registered in pytest.ini are slow, integration (requires MongoDB), unit (no external
dependencies) and notebook.
pytest hera/tests/ -v -m unit # only tests explicitly marked unit
pytest hera/tests/ -v -m "not integration"
pytest hera/tests/ -v -m "not notebook" # what make test and CI run
Not every test carries a marker, so -m unit selects a subset of the DB-free tests. No test in master is
currently marked slow, so -m "not slow" deselects nothing.
Choose a Result Set¶
# Via CLI option (defined in conftest.py)
pytest hera/tests/ --result-set BASELINE -v
# Via environment variable
export RESULT_SET=BASELINE
pytest hera/tests/ -v
The result set only selects the directory returned by the expected_dir fixture; no test in master
currently compares against expected files (see Expected Output Management).
Run with Short Traceback¶
pytest.ini already sets addopts = -v --tb=short. Use --tb=long for full tracebacks.
Parallel Workers¶
pytest-xdist is not in requirements.txt. The session fixture always uses the fixed project name
PYTEST_HERA_PROJECT and purges it on teardown, so parallel workers would share (and delete) the same project.
Continuous Integration¶
.github/workflows/ci.yml runs on every pull request to master. The Python job (test):
- Ubuntu, Python 3.11,
libgdal-dev gdal-bin,pip install -r requirements.txtandpip install -e . --no-deps - A
mongo:latestservice on port 27017 (root userhera/heracles); a step writes~/.pyhera/config.jsonfor the runner user (databasehera_ci) - Checks out
KaplanOpenSource/hermesandKaplanOpenSource/pyargosinto_vendor/and puts them onPYTHONPATH TEST_HERA=/home/runner/hera_unittest_data; the data is cached by the version in the bucket'slatest.jsonand fetched withbootstrap_unittest_data.shon a cache miss- Runs
pytest hera/tests/ -v -m "not notebook"withMPLBACKEND=Agg(andJUPYTER_PLATFORM_DIRS=1to silence a jupyter_client warning)
The same workflow has three UI jobs: ui-client (npx tsc --noEmit, npm run test, vite build),
ui-server (pytest tests in ui/server/) and ui-integration (vitest integration tests against a MongoDB service).
Notebook tests are not run in CI.
test_repository.json — Test Data Mapping¶
The file $TEST_HERA/test_repository.json maps test data files to Hera toolkit datasources
using the standard Hera repository JSON format. All entries use "isRelativePath": "True", and the
session fixture passes $TEST_HERA as basedir, so paths are relative to the test data root.
| Toolkit Key | Config | DataSources |
|---|---|---|
GIS_Raster_Topography |
defaultSRTM: SRTMGL1 |
SRTMGL1 → measurements/GIS/raster (directory, format: string) |
GIS_LandCover |
defaultLandCover: lc_mcd12q1 |
lc_mcd12q1 → measurements/GIS/raster/lc_mcd12q1.tif (format: string) |
GIS_Demography |
— | lamas_population → measurements/GIS/vector/population_lamas.shp (format: geopandas) |
MeteoLowFreq |
— | YAVNEEL → measurements/meteorology/lowfreqdata/YAVNEEL.parquet (format: parquet) |
MeteoHighFreq |
— | slicedYamim_sonic.parquet + slicedYamim_TRH.parquet → measurements/meteorology/highfreqdata/ (format: parquet) |
To add new test data, add entries to this JSON and they will automatically be loaded into the test project.
See also: Repository Examples and Repository Schema Reference
Test Modules — Detailed Description¶
test_datalayer.py¶
Tests for hera.datalayer against a real MongoDB (96 tests). It does not use the shared session project:
it defines its own fixtures proj (module-scoped, project pytest_datalayer_comprehensive) and clean_proj
(function-scoped, project pytest_datalayer_func). DB tests are skipped when MongoDB is unreachable.
| Area | Test classes |
|---|---|
| CRUD on the three collections | TestMeasurementsCRUD, TestSimulationsCRUD, TestCacheCRUD, TestSimulationsCacheAsDict |
| Queries | TestNestedQueries, TestGetAllDocuments, TestGetDocumentByID, TestGetMetadata, TestAddDocumentFromDict, TestEmptyProjectEdgeCases |
| Counters and config | TestCounters, TestConfiguration, TestProjectProperties |
| Saving data and handlers | TestSaveData, TestSaveDataAutoDetect, TestDataHandlers, TestDatatypes, TestGuessHandler |
| Collections and metadata frames | TestCollectionDirect, TestMetadataFrame, TestNonDBMetadataFrame |
| Other | TestAutoCache, TestExportImport, TestModuleFunctionsDB, TestModuleFunctionsLocal, TestParseConnectionString, TestConfigFileManagement |
Requires: MongoDB connection for the classes marked integration
test_repository.py¶
Tests for hera.utils.data.toolkit.dataToolkit (repository management). Uses its own module-scoped tk fixture.
| Test | Description |
|---|---|
test_add_repository |
Register a repository JSON via addRepository |
test_get_repository |
Retrieve and verify loaded JSON content |
test_load_datasources_to_project |
Full round-trip: load repository JSON, assert correct document count |
test_resolve_relative_paths |
Verify isRelativePath handling produces absolute paths |
test_absolute_paths_unchanged |
Verify absolute paths are not modified |
test_load_repository_from_path |
Test the direct-load method (no MongoDB) |
test_load_repository_nonexistent |
Verify FileNotFoundError for missing files |
Requires: MongoDB connection (for add/get/load tests), test JSON in repository/testCases/
test_topography.py¶
Tests for hera.measurements.GIS.raster.topography.TopographyToolkit.
Uses the topo_toolkit fixture from conftest (backed by project datasource SRTMGL1).
| Test | Description |
|---|---|
test_basic (getPointElevation) |
Single point elevation lookup |
test_second_file |
Elevation from a different HGT tile |
test_matches_hgt_file |
Verify toolkit result matches raw HGT binary read |
test_basic (getPointListElevation) |
Elevation for multiple points |
test_matches_hgt_files |
Multi-point comparison against raw HGT data |
test_basic (getElevationOfXarray) |
Elevation grid via xarray Dataset |
test_matches_hgt_file (xarray) |
Xarray grid comparison against raw HGT data |
test_basic (getElevation) |
Area elevation via bounding box |
test_matches_hgt_file (area) |
Area elevation comparison against raw HGT data |
test_basic (convertPointsCRS) |
CRS conversion (WGS84 -> ITM) |
test_single_point_no_deprecation_warning |
Single-point conversion emits no deprecation warning |
test_single_point_matches_multi_point_conversion |
Single-point and multi-point conversions agree |
test_basic (createElevationSTL) |
STL string generation |
test_basic (getElevationSTL) |
STL from existing Dataset |
test_basic (calculateStatistics) |
Mean, min, max statistics |
Data source: SRTMGL1 (HGT directory path via getDataSourceData). Tests skip when the required tile is missing.
test_landcover.py¶
Tests for hera.measurements.GIS.raster.landcover.LandCoverToolkit.
Uses the lc_toolkit fixture from conftest (backed by project datasource lc_mcd12q1).
The whole module is skipped when $TEST_HERA/measurements/GIS/raster/lc_mcd12q1.tif does not exist.
| Test | Description |
|---|---|
test_basic (getLandCoverAtPoint) |
Land cover value at a single point |
test_against_raster |
Compare toolkit result with raw rasterio read |
test_basic (getLandCover) |
Land cover map for a bounding box |
test_map_vs_raster |
Sampled map values vs. raster file |
test_at_point (roughness) |
Roughness at a point |
test_area (roughness) |
Roughness map for a bounding box |
test_values_in_range |
Verify roughness values are within expected range |
test_roughnesslength2sandgrainroughness |
Conversion function |
test_known_landcover |
Known land cover value -> expected roughness |
test_out_of_bounds |
IndexError for out-of-bounds coordinates |
test_get_coding_map |
Coding map structure and values |
Data source: lc_mcd12q1 (file path via getDataSourceData, opened with rasterio by toolkit)
test_lowfreq.py¶
Tests for hera.measurements.meteorology.lowfreqdata.toolkit.lowFreqToolKit.
Uses the lf_toolkit fixture from conftest (backed by project datasource YAVNEEL).
| Category | Tests |
|---|---|
| Toolkit Init | test_has_analysis, test_has_presentation, test_has_docType, test_docType_value |
| Analysis | test_basic (addDatesColumns), test_max_normalized, test_density, test_y_normalized_behaviour, test_basic (resampleSecondMoments) |
| Presentation | test_plotScatter, test_dateLinePlot, test_plotProbContourf, test_plotProbContourf_bySeason |
| Data Matching | test_dateLinePlot_matches_data, test_plotScatter_matches_data |
| Edge Cases | test_scatter_empty_dataframe, test_scatter_nan_and_outliers, test_scatter_WS_field |
| Distribution | test_contourf_distribution_ranges |
| Save | test_scatter_creates_non_empty_image |
Data source: YAVNEEL (parquet via getDataSourceData, returns dask DataFrame → .compute())
test_highfreq.py¶
Tests for hera.measurements.meteorology.highfreqdata toolkit, analysis calculators, and turbulence statistics.
Uses the hf_toolkit fixture from conftest (backed by datasources slicedYamim_sonic and slicedYamim_TRH).
| Category | Tests |
|---|---|
| Toolkit | test_docType_property |
| Data Reading | test_read_sonic_data, test_read_trh_data, test_read_nonexistent_datasource |
| Time Range | test_sonic_time_range, test_trh_time_range |
| Specific Points | test_sonic_first_row, test_trh_first_row |
| Error Paths | test_campbelToParquet_nonexistent, test_asciiToParquet_nonexistent |
| AbstractCalculator | test_init_basic, test_sampling_window, test_compute_methods_exist, test_set_save_properties |
| MeanDataCalculator | test_calculate_mean, test_hour_and_timeWithinDay, test_horizontalSpeed, test_sigma_sigmaH, test_Ustar_and_uStarOverWindSpeed, test_compute_returns_dataframe |
| Advanced MeanData | test_TKE, test_MOLength |
| RawdataAnalysis | test_singlePointTurbulenceStatistics_returns_instance, test_singlePointTurbulenceStatistics_raises_on_invalid, test_AveragingCalculator, test_AveragingCalculator_raises_on_invalid |
| Turbulence Stats | test_instantiation, test_invalid_input_type, test_fluctuations, test_secondMoments, test_sigma, test_horizontalSpeed, test_Ustar, test_TKE, test_MOLength_Sonic |
Data sources: slicedYamim_sonic, slicedYamim_TRH (parquet via getDataSourceData). Skipped when the files are missing.
test_demography.py¶
Tests for hera.measurements.GIS.vector.demography.DemographyToolkit (54 tests).
DB-backed tests use the demo_toolkit fixture from conftest (backed by project datasource lamas_population);
others use synthetic GeoDataFrames.
| Test class | Covers |
|---|---|
TestDemographyToolkitInit |
analysis / presentation properties, population types |
TestSetDefaultDirectory |
Directory creation and path assignment, error when missing and create=False |
TestCalculatePopulationInPolygon |
Full/partial/no intersection, invalid datasource, known values, GeoDataFrame input, population types |
TestCreateNewArea |
New area creation and total population |
TestPlotPopulationDensity, TestPlotPopulation, TestPlotPopulationByType, TestPlotPopulationInPolygon, TestPlotArea, TestPlotPopulationOnMap |
Presentation layer plots and their options |
TestEdgeCases |
Empty GeoDataFrame, single polygon, no overlap |
Data source: lamas_population (geopandas via getDataSourceData). DB-backed tests skip when the shapefile is missing.
Other test modules¶
| Module | What it covers | Needs |
|---|---|---|
test_repository_export.py |
hera.utils.data.repositoryExport: content hashes, document → repository item, merge, dedup, round trip |
DB-free, except TestExportFacade / TestRoundTrip (temporary project in MongoDB) |
test_experiment.py |
experimentHome, trials, entity types, data engines, analysis/presentation, Argos zip parsing |
MongoDB, argos for some tests |
test_toolkit_coverage.py |
Pure-logic paths of Topography, LSM template params, OFToolkit, Briggs rural sigmas, lowfreq addDatesColumns |
None (unit) |
test_riskassessment_flow.py |
Risk assessment agent, injury levels, toxic loads, full mock flow | None (unit) |
test_matplotlibContour.py |
hera.utils.matplotlibCountour contour → GeoDataFrame conversion |
None (unit) |
test_of_lsm_flow.py |
OFLSMToolkit Lagrangian particle-file parsing |
hermes; blockMesh for the full OpenFOAM test |
test_hermes_workflow.py |
Running a hermes workflow through hermesWorkflowToolkit |
hermes, luigi |
test_workflow_execution.py |
Luigi command construction and dispatch_id output isolation |
hermes, luigi for the integration test |
test_logging_helpers.py |
Default logging config creation | None |
test_no_invalid_escapes.py |
Every hera/**/*.py compiles without invalid-escape warnings |
None |
test_notebooks.py |
Executes every repository notebook (marker notebook) |
Jupyter kernel; excluded from make test and CI |
unit/ |
test_cli_import_cost.py, test_diffJSONS.py, test_lowfreq_docs_match_code.py, test_openfoam_dataset2of.py |
None |
dynamic_loading_tests_pack/ |
Dynamic toolkit loading via classpath (data in dynamic_loading/), dynamic experiment loading, hera-experiment CLI shortcuts |
MongoDB, the hera-experiment script on PATH and argos for the experiment tests |
Shared Fixtures (conftest.py)¶
Session-Scoped Project Fixtures¶
| Fixture | Description |
|---|---|
test_hera_root |
Validated path to $TEST_HERA (default ~/hera_unittest_data); skips if missing |
data_config |
Parsed data_config.json dict |
result_set |
Active result-set name |
expected_dir |
Path to expected/<result_set>/; skips if missing |
hera_test_project |
The shared Hera Project with all test data loaded from test_repository.json |
hera_project_name |
The string "PYTEST_HERA_PROJECT" |
_no_trace_guard |
Autouse. Snapshots the project list at session start and purges every project (DB documents and directories) created during the session, plus leftovers matching test name patterns |
Per-Toolkit Fixtures (session-scoped)¶
| Fixture | Toolkit Class | Data Sources |
|---|---|---|
topo_toolkit |
TopographyToolkit |
SRTMGL1 (HGT directory) |
lc_toolkit |
LandCoverToolkit |
lc_mcd12q1 (TIF path) |
demo_toolkit |
DemographyToolkit |
lamas_population (SHP → GeoDataFrame) |
lf_toolkit |
lowFreqToolKit |
YAVNEEL (parquet → dask/pandas) |
hf_toolkit |
HighFreqToolKit |
slicedYamim_sonic, slicedYamim_TRH (parquet) |
Lightweight Fixtures¶
| Fixture | Scope | Description |
|---|---|---|
project_fixture |
function | Temporary Project pytest_temp_project with cleanup |
data_toolkit_fixture |
session | dataToolkit instance |
These two are available but not used by any test module in master (test_datalayer.py and
test_repository.py define their own fixtures).
Cleanup Helpers¶
purge_project(projectName) (= purge_project_db + purge_project_dirs) deletes every document of a project
in all three collections, including the hidden config document, and removes ~/.hera/<projectName>.
Use it in fixtures that create their own projects.
Comparison Helpers¶
Available in conftest.py for use in tests:
from hera.tests.conftest import compare_dataframes, compare_dataarrays, compare_outputs
# DataFrame comparison with numeric tolerance
assert compare_dataframes(result_df, expected_df, rtol=1e-6, atol=1e-6)
# DataArray comparison
assert compare_dataarrays(result_da, expected_da)
# Type-based comparison (supports: dataframe, geodataframe, xarray, float, dict, etc.)
assert compare_outputs(result, expected, "dataframe")
For more details on the comparison system, see Test Flow.
dataToolkit Helper Methods¶
Two static methods on hera.utils.data.toolkit.dataToolkit support direct loading without MongoDB:
loadRepositoryFromPath(json_path) (static)¶
from hera.utils.data.toolkit import dataToolkit
repo = dataToolkit.loadRepositoryFromPath("/path/to/repository.json")
# Returns dict with all relative resource paths resolved to absolute
resolveDataSourcePaths(repositoryJSON, basedir) (static)¶
resolved = dataToolkit.resolveDataSourcePaths(repo_dict, basedir="/data/root")
# Deep-copies the dict and resolves all relative resource paths
Troubleshooting¶
Tests are skipped¶
- "TEST_HERA directory not found" — Set
TEST_HERAenv var or runmake testto download the data - "test_repository.json not found" / "data_config.json not found" — The data directory is incomplete; re-run
./scripts/s3/bootstrap_unittest_data.sh - "Skipping landcover tests — data file not found" —
TEST_HERAis unset or the TIF is not in the snapshot - "... data file missing in TEST_HERA" / "Required elevation tile missing" — The file is not part of the downloaded snapshot (see the warning under Test Data Repository)
- "datasource not loaded in project" — Verify MongoDB is running and the repository JSON is valid
- "MongoDB not reachable" — See below
MongoDB connection errors¶
All toolkit tests (topography, landcover, demography, lowfreq, highfreq) require an active MongoDB instance.
The session-scoped hera_test_project fixture loads data into MongoDB at startup and purges it on teardown.
Check ~/.pyhera/config.json and make mongo-status.
Matplotlib backend issues¶
Presentation tests (plots) may require a non-interactive backend:
See also: Troubleshooting
Adding New Test Data¶
- Place the data file under
$TEST_HERA/measurements/<appropriate_subdir>/ - Add an entry to
$TEST_HERA/test_repository.jsonunder the appropriate toolkit key - The data will be automatically loaded into the test project on the next test run
- In your test module, access the data via
toolkit.getDataSourceData("your_datasource_name")
The copy in the S3 bucket is what CI and make test download; a file that exists only on your machine
makes the dependent tests skip elsewhere.
Adding New Tests¶
Step-by-Step Guide¶
- Add test data to
$TEST_HERA/measurements/<subdir>/ - Update
test_repository.jsonwith a new entry under the appropriate toolkit key - Add a fixture in
conftest.py(session-scoped, depends onhera_test_project) - Create a test module
hera/tests/test_<name>.py - Use the fixture to get a real toolkit instance — no file paths in tests
- Skip, don't fail, on missing data — follow the existing modules (
pytest.skipwhengetDataSourceDatareturnsNoneor the file is absent) - Optionally compare outputs using
compare_outputs()and files underexpected/<result_set>/
Example: Adding a New Toolkit Test¶
# In conftest.py — add a session-scoped fixture
@pytest.fixture(scope="session")
def my_toolkit(hera_test_project):
from hera.my_module import MyToolkit
return MyToolkit(projectName=PYTEST_PROJECT_NAME)
# In test_my_toolkit.py
class TestMyToolkit:
def test_basic(self, my_toolkit):
data = my_toolkit.getDataSourceData("my_datasource")
assert data is not None
# ... assertions ...
Related Documentation¶
- Test Flow — Deep dive into the Pytest session lifecycle and comparison system
- Installation & Setup — Environment, MongoDB and
config.json - Repository Examples — Examples of
test_repository.jsonstructure - Repository Schema Reference — Complete schema documentation
- Environment Variables — All test-related environment variables