Skip to content

Comments

Improve unit tests - reuse code via test fixtures, test behavoirs#699

Merged
dylanhmorris merged 22 commits intomainfrom
mem_690_unit_test_improvements
Feb 12, 2026
Merged

Improve unit tests - reuse code via test fixtures, test behavoirs#699
dylanhmorris merged 22 commits intomainfrom
mem_690_unit_test_improvements

Conversation

@cdc-mitzimorris
Copy link
Collaborator

Summary

Replace coverage-driven tests with test of behavoir and correctness.

  • Replace low-value tests (shape-only assertions, private method tests) with tests that validate real-world behavior
  • Consolidate shared fixtures in conftest.py, remove 5 dead fixtures, add 4 reusable fixtures (gen_int_rv, hierarchical_normal_noise, hierarchical_normal_noise_tight, hierarchical_infections)
  • Extract shared non-fixture test code (ConcreteMeasurements, create_mock_infections) to new test/test_helpers.py module
  • Test base class no-ops and validation stubs in file test/test_interface_coverage.py

Changes by file

test/conftest.py

Removed 5 dead fixtures, added 4 shared fixtures.

Dead fixtures removed (never used by any test file):

  • medium_delay_pmf
  • counts_process_medium_delay
  • counts_process_realistic
  • simple_shedding_pmf
  • medium_shedding_pmf

Dead fixtures removed (replaced by new shared fixtures):

  • sensor_mode_rv, sensor_sd_rv
  • sensor_mode_rv_tight, sensor_sd_rv_tight

New shared fixtures added:

  • gen_int_rv -- COVID-like 7-day generation interval
  • hierarchical_normal_noise -- standard HierarchicalNormalNoise with VectorizedRV
  • hierarchical_normal_noise_tight -- tight variance version for near-deterministic testing
  • hierarchical_infections -- pre-configured HierarchicalInfections instance

test/test_helpers.py (new file)

Shared non-fixture test code extracted here (since test/ is a package, conftest.py cannot be directly imported by test modules):

  • ConcreteMeasurements class (concrete implementation of abstract Measurements for testing)
  • create_mock_infections() function (generates spike, constant, or decay infection curves)

test/test_temporal_processes.py

Added:

  • test_ar1_mean_reversion -- verifies AR1 trajectories revert toward zero
  • test_differenced_ar1_trend_persistence -- verifies DifferencedAR1 produces persistent trends

test/test_hierarchical_priors.py

Strengthened:

  • Shape-only tests now include value assertions (centering near zero for Normal/StudentT, positivity for Gamma)

test/test_hierarchical_infections.py

Added:

  • test_infections_are_positive -- verifies all infection values are positive (epidemiological invariant)
  • test_shape_and_positivity_across_subpop_counts -- parametrized over K=1,3,6 with positivity and weighted-sum checks

Now uses conftest fixtures (gen_int_rv, hierarchical_infections) instead of local fixtures.

test/test_observation_measurements.py

Added:

  • test_log_scale_correctness -- verifies output equals log(convolved infections) with known inputs
  • test_sensor_bias_differences -- verifies hierarchical noise produces sensor-specific biases

Strengthened:

  • test_sample_shape now also verifies sensor variation and log-scale output

test/test_observation_counts.py

Added:

  • test_convolution_hand_computable -- 1000 infections on day 10 with PMF [0.5, 0.5] should produce 500 on days 10 and 11
  • test_observation_passthrough -- providing obs=known_values returns those exact values
  • test_poisson_mean_approximation -- mean of 50 Poisson samples approximates expected rate

Strengthened:

  • test_zero_infections now asserts predicted == 0 (not just shape)
  • test_small_infections now asserts plausible range on predicted values
  • test_sample_returns_correct_shape now includes non-negative value assertions

test/test_pyrenew_builder.py

Added:

  • test_prior_predictive_multi_signal -- uses numpyro.infer.Predictive to draw prior predictive samples from a builder-constructed model; verifies shapes and positivity

Strengthened:

  • test_run_with_population_structure now also asserts all infection samples are positive

test/test_interface_coverage.py (new file)

Tests interface contracts (repr, validate(), infection_resolution(), get_required_lookback()) across implementing classes via parametrized tests

@codecov
Copy link

codecov bot commented Feb 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.85%. Comparing base (d260ea5) to head (4f5534a).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #699      +/-   ##
==========================================
+ Coverage   97.73%   97.85%   +0.12%     
==========================================
  Files          51       51              
  Lines        1542     1542              
==========================================
+ Hits         1507     1509       +2     
+ Misses         35       33       -2     
Flag Coverage Δ
unittests 97.85% <ø> (+0.12%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link

github-actions bot commented Feb 10, 2026

Thank you for your contribution @cdc-mitzimorris 🚀! Your github-pages is ready for download 👉 here 👈!
(The artifact expires on 2026-02-18T19:12:36Z. You can re-generate it by re-running the workflow here.)

cdc-mitzimorris and others added 2 commits February 11, 2026 11:56
Resolve merge conflicts from PR 698 (validate_data delegation):
- test_observation_counts.py: keep PR 699 structure (TestCountsValidation)
- test_pyrenew_builder.py: adopt PR 698 validation_builder fixture,
  hospital_subpop keys, updated error patterns, and new validation tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@cdc-mitzimorris
Copy link
Collaborator Author

cdc-mitzimorris commented Feb 11, 2026

per code review from coderabbit (run by claude.ai):

Plan: Implement Valid Code Review Recommendations

Context

A code review identified issues in the PyRenew test suite on branch mem_690_unit_test_improvements. After critical evaluation, a subset of findings are valid and worth implementing. This plan addresses dead code, missing assertions, weak assertions, non-deterministic tests, missing unit tests, and unused fixtures.

Changes

  1. Remove dead code in test/test_latent_infections.py

Lines 32-37: Delete the orphaned Infections()() call whose return value is discarded. The obs dict (lines 27-31) and inf1 (line 25) are already used correctly below.

  1. Fix unseeded np.random in test/test_observation_negativebinom.py

Line 22: Replace np.random.randint(1, 5, size=10) with a fixed array like np.array([3, 1, 4, 2, 3, 1, 4, 2, 3, 1]) for deterministic test input.

  1. Add assertions to test/test_infection_initialization_process.py

Lines 41-43: The loop samples 3 models but asserts nothing. Add assertions for each:

  • All results have shape (n_timepoints,) i.e. (10,)
  • zero_pad_model result has leading zeros (all but last element are 0)
  • exp_model result is all positive (exponential growth from a LogNormal I0)
  • vec_model result equals jnp.arange(n_timepoints) (identity passthrough)
  1. Fix misleading docstring in test/test_pyrenew_builder.py

Line 347: Change docstring from "Test that validate() method calls _validate()." to "Test that validate() succeeds on a valid model." — the test only checks it doesn't raise.

  1. Strengthen NaN-padding test in test/test_observation_counts.py

Lines 253-268 (test_dense_observations_with_nan_padding): Add assertion that the predicted values are non-NaN (the observation process should produce predictions for all
days regardless of NaN observations).

  1. Strengthen negative binomial test in test/test_observation_negativebinom.py

Lines 36-58 (test_negativebinom_random_obs): Add assertion that the sample mean is close to the expected rate (5.0), not just that two samples agree with each other.

  1. Add unit tests for pad_observations() and shift_times()

File: test/test_pyrenew_builder.py — add a new test class TestMultiSignalModelHelpers:

  • test_pad_observations_prepends_nans: verifies correct NaN count, shape, float conversion of int input
  • test_shift_times_adds_offset: verifies times are shifted by n_initialization_points
  1. Clean up unused fixtures in test/conftest.py

Remove the 3 fixtures that have zero usage across the test suite:

  • realistic_delay_pmf (lines 53-63)
  • constant_infections (lines 256-266)
  • constant_infections_2d (lines 269-279)

Files to Modify

  1. test/test_latent_infections.py — remove dead code
  2. test/test_observation_negativebinom.py — fix seed, strengthen assertion
  3. test/test_infection_initialization_process.py — add assertions
  4. test/test_pyrenew_builder.py — fix docstring, add helper tests
  5. test/test_observation_counts.py — strengthen NaN test
  6. test/conftest.py — remove unused fixtures

Verification

Run python -m pytest test/ -x -q to confirm all tests pass after changes.

@dylanhmorris dylanhmorris merged commit 00352ea into main Feb 12, 2026
8 checks passed
@dylanhmorris dylanhmorris deleted the mem_690_unit_test_improvements branch February 12, 2026 15:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants