Kerykeion's test suite lives in tests/core/ with 27 test files and parallel execution via pytest-xdist (-n 8).
Tests are run through 4 hierarchical tiers (core < base < medium < extended).
# Test — 4 tiers, each includes everything from the previous one
poe test:core # ~1,750 tests — every module, no exhaustive matrix
poe test:base # ~6,300 tests — adds exhaustive matrix (DE440s, 1849-2150)
poe test:medium # ~7,000 tests — adds DE440 subjects (1550-2650)
poe test:extended # ~7,900 tests — all subjects, full ephemeris range
# Coverage — same tiers with terminal + HTML report (htmlcov/)
poe test:core:cov # Coverage on core tier
poe test:base:cov # Coverage on base tier
poe test:medium:cov # Coverage on medium tier
poe test:extended:cov # Coverage on extended tier (full)
# Regenerate golden standards
poe regenerate:svg # SVG chart baselines (tests/data/svg/)
poe regenerate:reports # Report golden files (tests/fixtures/)
poe regenerate:positions # Expected positions & subjects (tests/data/expected_*.py)
poe regenerate:aspects # Expected aspects (tests/data/expected_*_aspects.py)
poe regenerate:all # All of the aboveRuns 22 of the 27 test files — one per module/concern. This tier exercises every code path in Kerykeion: subject creation, chart drawing, aspects, reports, composite subjects, planetary returns, ephemeris data, transits, relationship scores, context serialization, settings, utilities, backward compatibility, Arabic parts, house comparison, moon phases, and geonames.
It excludes the 5 exhaustive matrix files that generate thousands of parametrized combinations:
| Excluded file | What it does | Tests |
|---|---|---|
test_houses_positions.py |
Every house system x temporal/geographic subject x cusp | ~2,060 |
test_planetary_positions.py |
Every planet x temporal/geographic subject | ~1,740 |
test_moon_phase_historical_verification.py |
2,042 historical moon phase cases | ~2,040 |
test_subject_factory_parametrized.py |
Every house system/sidereal mode/perspective x subjects | ~280 |
test_chart_parametrized.py |
Temporal/geographic x themes/house systems cross-products | ~90 |
Use test:core for fast local development feedback.
Includes all 27 test files (core + the 5 matrix files above), but restricts temporal subjects to the DE440s ephemeris range (1849-2150, 11 subjects). This is the recommended CI tier — it catches regressions across the full matrix without requiring extended ephemeris files.
Same as base, but extends the temporal range to the DE440 ephemeris (1550-2650, 16 subjects). Adds Renaissance, Galileo, Newton, and far-future subjects.
Runs everything with all 24 temporal subjects spanning from 100 AD to 2650 AD (DE441, full range). The 60 skipped tests are SVG baselines that gracefully skip when the expected file doesn't exist.
tests/
├── conftest.py # Tier filtering, parametrized fixtures, session subjects
├── core/ # All 27 test files
│ ├── conftest.py # Session fixtures, SVG/report comparison helpers
│ ├── test_arabic_parts.py
│ ├── test_aspects.py
│ ├── test_astrological_subject.py
│ ├── test_astrological_subject_jyotish.py
│ ├── test_backward_compatibility.py
│ ├── test_chart_data_factory.py
│ ├── test_chart_drawer.py
│ ├── test_chart_parametrized.py
│ ├── test_composite_subject.py
│ ├── test_context_serializer.py
│ ├── test_draw_planets.py
│ ├── test_ephemeris_data.py
│ ├── test_fetch_geonames.py
│ ├── test_house_comparison.py
│ ├── test_houses_positions.py
│ ├── test_json_dump.py
│ ├── test_lunar_phase_svg.py
│ ├── test_moon_phase_details_factory_mocked.py
│ ├── test_moon_phase_historical_verification.py
│ ├── test_planetary_positions.py
│ ├── test_planetary_return.py
│ ├── test_relationship_score.py
│ ├── test_report.py
│ ├── test_settings.py
│ ├── test_subject_factory_parametrized.py
│ ├── test_transits.py
│ └── test_utilities.py
├── data/ # Shared test data
│ ├── compare_svg_lines.py # SVG line-by-line comparison utility
│ ├── expected_natal_aspects.py # Golden natal aspect data
│ ├── expected_synastry_aspects.py # Golden synastry aspect data
│ ├── expected_positions.py # Expected planetary positions per subject
│ ├── expected_aspects.py # Expected aspects per subject
│ ├── expected_astrological_subjects.py
│ ├── expected_arabic_parts.py
│ ├── test_subjects_matrix.py # Subject matrix: 24 temporal, 16 geographic
│ ├── configurations/ # Settings override JSON files
│ └── svg/ # 286 SVG baseline files
└── fixtures/ # Golden-file report snapshots (36 .txt files)
Defined in tests/data/test_subjects_matrix.py:
Cover centuries from 100 AD to 2650 AD, exercising all three ephemeris tiers:
- Base (DE440s, 1849-2150): modern_1990, john_lennon_1940, einstein_1879, ww2_end_1945, moon_landing_1969, y2k_2000, near_future_2030, mid_future_2050, late_future_2100, early_modern_1900, late_victorian_1880
- Medium (DE440, 1550-2650): renaissance_1600, galileo_1564, newton_1643, far_future_2200, distant_future_2500
- Extended (DE441): ancient_rome_100ad, medieval_800, viking_era_1000, crusades_1200, columbus_1492, bach_1685, napoleon_1769, deep_future_2650
Latitude diversity from 66S to 66N:
- Equatorial: quito_equator, singapore_1n, nairobi_1s
- Tropical: mumbai_19n
- Mid-latitude: rome_41n, new_york_40n, tokyo_35n, london_51n, berlin_52n, sydney_34s, buenos_aires_34s, cape_town_34s
- High-latitude: stockholm_59n, anchorage_61n
- Polar-adjacent: antarctic_circle_66s, ushuaia_55s
- House Systems (23): Placidus, Koch, Whole Sign, Equal, Campanus, Regiomontanus, Porphyry, Morinus, Alcabitius, Carter, Horizon, Sunshine, etc.
- Sidereal Modes (20): Lahiri, Fagan-Bradley, DeLuce, J2000, Raman, Ushashashi, Krishnamurti, Hipparchos, etc.
- Perspective Types (4): Apparent Geocentric, True Geocentric, Heliocentric, Topocentric
- Synastry Pairs (6): john_lennon + yoko_ono, john_lennon + paul_mccartney, etc.
| File | Tests | What it covers |
|---|---|---|
test_astrological_subject.py |
101 | Subject creation, all planet/house accessors, zodiac configs, edge cases (midnight, leap year, DST), Arabic parts, vertex, fixed stars, TNOs, error handling, is_diurnal |
test_astrological_subject_jyotish.py |
31 | Sidereal (Lahiri) subject with exact position regression values |
test_json_dump.py |
24 | JSON serialization of subject data |
test_planetary_positions.py |
14 | Parametrized exact planetary position validation against expected data |
test_houses_positions.py |
16 | House position validation across temporal/geographic/system variations |
| File | Tests | What it covers |
|---|---|---|
test_chart_data_factory.py |
75 | Single/dual chart creation, all chart types (natal/synastry/transit/composite/return), element/quality distributions, aspect calculations, parameter validation, serialization, edge cases |
test_composite_subject.py |
68 | Midpoint composite creation, commutativity, incompatible configs, custom names, planet/house attributes, Davison method, edge cases |
test_ephemeris_data.py |
34 | Daily/hourly/minutely ephemeris, planetary movement rates, model output, step validation, cross-year boundary, configuration variants (sidereal, Koch, geocentric, DST) |
test_planetary_return.py |
62 | Solar/lunar return calculation, return sun/moon position accuracy, house system variations, location variants, deprecated API tests, online mode validation |
test_relationship_score.py |
63 | Score calculation, aspect evaluation rules, destiny sign, score descriptions, breakdown structure, exact regression scores for 4 canonical couples |
test_subject_factory_parametrized.py |
18 | Cross-product: all house systems x subjects, all sidereal modes x subjects, all perspectives x subjects, temporal/geographic coverage, configuration consistency |
test_transits.py |
17 | TransitsTimeRangeFactory initialization, transit detection, custom points/aspects, empty/single ephemeris edge cases |
| File | Tests | What it covers |
|---|---|---|
test_aspects.py |
66 | Natal/synastry aspects with expected data, aspect types/degrees validation, movement calculation (applying/separating/static), edge cases (boundary crossing, retrograde, epsilon handling, non-standard aspects like quintile/septile), planet_id_decoder, axis orb filter |
| File | Tests | What it covers |
|---|---|---|
test_chart_drawer.py |
193 | All chart types (natal, synastry, transit, composite, return), all themes (classic, dark, light, high-contrast, B&W, strawberry), all sidereal modes (18 parametrized), all house systems (23 parametrized), 10 languages, partial views (wheel-only, aspect-grid-only), chart options (padding, CSS, minify, custom title, indicators), SVG baseline comparison, save methods, error handling, large aspect lists, overlapping planets, composite location |
test_chart_parametrized.py |
9 | Temporal x themes cross-product, geographic x house systems, extreme latitude whole-sign, sidereal x theme combinations, house system synastry/transit |
test_draw_planets.py |
75 | Planet glyph positioning, retrograde markers, degree labels, planet grouping/overlap handling, edge cases (empty list, single planet, zero/359 degrees), SVG output structure, chart type variants, internal helpers |
test_lunar_phase_svg.py |
5 | All 8 standard moon phases match reference SVG sheet |
| File | Tests | What it covers |
|---|---|---|
test_report.py |
110 | Subject/natal/synastry/transit/composite/return reports, moon phase overview, golden-file snapshots (36 baseline files), section presence, content formatting (retrograde markers, aspect symbols, movement, speed, declination, position, dates, coordinates), element/quality percentage sums, max_aspects truncation, sidereal mode display, empty data paths, relationship score content, cusp comparison, active points/aspects presets, geographic/temporal diversity, private helpers, parametrized sweeps, composite houses, subject-only mode |
| File | Tests | What it covers |
|---|---|---|
test_backward_compatibility.py |
66 | Legacy AstrologicalSubject wrapper, KerykeionChartSVG wrapper, NatalAspects/SynastryAspects wrappers, kr_types module aliases, deprecation warnings, migration path examples, disable_chiron params, zodiac type normalization, settings file param warnings, custom active aspects, legacy chart type validation, SubscriptableBaseModel operations, ISO datetime parsing with Z suffix, active aspects passthrough |
| File | Tests | What it covers |
|---|---|---|
test_context_serializer.py |
72 | Point/lunar phase/aspect/element/quality/subject/chart data to XML context, transit moments, transits time range, house comparison context, return subject context, moon phase overview, dispatcher, non-qualitative output validation |
| File | Tests | What it covers |
|---|---|---|
test_settings.py |
30 | Default/custom settings loading, language settings, translations (nested keys, missing keys, fallbacks, explicit language dict, loaded overrides), settings file validation |
| File | Tests | What it covers |
|---|---|---|
test_utilities.py |
91 | get_number_from_name, get_kerykeion_point_from_degree, logging setup, is_point_between, get_planet_house (including floating-point cusp boundary regression), circular_mean/circular_sort, moon emoji/name, polar latitude adjustment, find_common_active_points, Julian day conversion, calculate_moon_phase, inline_css_variables_in_svg (including no-style-block and no-fallback edge cases), distribute_percentages_to_100, house name/number conversion, chart utils internal functions, planet grid layout, element/quality distribution |
| File | Tests | What it covers |
|---|---|---|
test_fetch_geonames.py |
18 | Online lookup (marked @pytest.mark.online), mocked basic/error paths, cache filtering (transient errors, valid responses, invalid JSON, timezone), env config, private error paths (malformed payloads) |
| File | Tests | What it covers |
|---|---|---|
test_arabic_parts.py |
54 | Formula correctness (Pars Fortunae/Spiritus/Amoris/Fidei), day/night symmetry, result properties, auto-activation of dependencies, day/night detection (Sun altitude), geographic edge cases, sidereal mode, is_diurnal field, single-part-only activation |
test_house_comparison.py |
7 | Cusps/points in reciprocal houses, limited active points, HouseComparisonFactory end-to-end, malformed data handling |
test_moon_phase_details_factory_mocked.py |
35 | Moon phase details factory with mocked Swiss Ephemeris, phase identification, illumination, upcoming phases, eclipses, integration test |
test_moon_phase_historical_verification.py |
18 | 2,042-case historical moon phase verification |
- Tier filtering:
pytest_addoptionadds--tieroption;pytest_collection_modifyitemsskips subjects outside the selected tier - Session-scoped subjects:
john_lennon,paul_mccartney,johnny_depp(shared across all tests) - Parametrized fixtures:
temporal_subject_data,geographic_subject_data,house_system,sidereal_mode,perspective_type,synastry_pair_ids,planet_name,house_name,angle_name, etc. - Chart/aspect fixtures:
natal_chart_data,transit_chart_data,synastry_chart_data,natal_aspects - Edge-case fixtures:
polar_latitude_subjects,leap_year_subject,midnight_subject
- Session-scoped subjects:
johnny_depp,john_lennon,yoko_ono,paul_mccartney(usingAstrologicalSubjectFactory.from_birth_datawith explicit coordinates,online=False) - Comparison helpers:
assert_position_equal,assert_positions_match,assert_svg_matches_baseline,assert_report_matches_snapshot - Tolerance constants:
POSITION_TOLERANCE=0.01,SPEED_TOLERANCE=0.01,DECLINATION_TOLERANCE=0.01,ORB_TOLERANCE=0.1,PERCENTAGE_TOLERANCE=0.5 - SVG comparison: imports
compare_svg_linesfromtests.data.compare_svg_lines
SVG baseline files live in tests/data/svg/ (286 files). Tests compare generated SVGs line-by-line using compare_svg_lines(), which applies numeric tolerance for floating-point coordinates. If a baseline file is missing, the test is skipped gracefully.
Report golden files live in tests/fixtures/ (36 .txt files). The assert_report_matches_snapshot helper compares generated report output against these files.
-
Offline by default. All subjects use
online=False, suppress_geonames_warning=Truewith explicitlat,lng,tz_strcoordinates. Only tests marked@pytest.mark.onlinerequire network access. -
Parallel-safe. No shared mutable state between tests. Session-scoped fixtures create immutable subjects. Tests are distributed across 8 workers by default.
-
Tiered ephemeris. Historical and future test subjects are stratified by the JPL ephemeris file required. CI can run
test:basefor fast validation andtest:extendedfor full coverage. -
Graceful skip on missing baselines. SVG golden-file tests skip (not fail) when the expected baseline doesn't exist, allowing new chart types to be added without immediately generating baselines.
-
Semantic file organization. Each test file maps to a specific module or concern (e.g.,
test_chart_drawer.pycoverskerykeion.charts.chart_drawer,test_aspects.pycoverskerykeion.aspects). -
Parametrized coverage explosion. Configuration axes (house systems, sidereal modes, perspectives, temporal subjects, geographic subjects) are combined via
pytest.mark.parametrizeto achieve broad coverage with minimal test code.