Skip to content

Testing Checklist

Run these tests before adding a new preset to benchmark examples or documentation. Keep the first tests narrow — a slow or brittle test suite is worse than a simple one.

Minimum Required Tests

1. Preset registration

from seahorse import list_available_models
from seahorse import STPPEstimator

def test_preset_registered():
    assert "my_preset" in list_available_models()

def test_preset_constructs():
    model = STPPEstimator("my_preset", device="cpu")
    assert model is not None

2. Config loading

from seahorse import STPPConfig

def test_config_from_preset():
    cfg = STPPConfig.from_preset("my_preset")
    assert cfg.model.preset == "my_preset"

def test_config_roundtrip(tmp_path):
    cfg = STPPConfig.from_preset("my_preset")
    yaml_path = tmp_path / "config.yaml"
    cfg.to_yaml(str(yaml_path))
    cfg2 = STPPConfig.from_yaml(str(yaml_path))
    assert cfg2.model.preset == cfg.model.preset

3. One-epoch fit on tiny data

from seahorse import STPPEstimator, load_jsonl

def test_fit_tiny(tiny_train, tiny_val, tiny_test):
    model = STPPEstimator("my_preset", device="cpu")
    model.fit(
        tiny_train, tiny_val, tiny_test,
        epochs=1, batch_size=2,
    )
    scores = model.evaluate(tiny_test)
    assert "test_nll" in scores
    assert scores["test_nll"] < 0 or scores["test_nll"] > 0  # not NaN

Use tiny data (2–5 sequences, 3–5 events each) so the test finishes in seconds.

4. Save and reload

def test_save_load(tmp_path, tiny_train, tiny_val, tiny_test):
    model = STPPEstimator("my_preset", device="cpu")
    model.fit(tiny_train, tiny_val, tiny_test, epochs=1, batch_size=2)

    save_dir = model.save(str(tmp_path / "saved"))
    loaded = STPPEstimator.load(save_dir)

    scores_orig   = model.evaluate(tiny_test)
    scores_loaded = loaded.evaluate(tiny_test)
    assert abs(scores_orig["test_nll"] - scores_loaded["test_nll"]) < 1e-4

5. CLI core evaluation

python -m seahorse fit \
  --preset my_preset \
  --train data/tiny/train.jsonl \
  --val data/tiny/val.jsonl \
  --test data/tiny/test.jsonl \
  --out runs/test_my_preset \
  --override training.n_epochs=1 training.batch_size=2 data.num_workers=0

python -m seahorse evaluate metrics \
  --run runs/test_my_preset/fit/my_preset/<run_id> \
  --data data/tiny/test.jsonl \
  --split test \
  --metric-profile core \
  --out runs/test_my_preset/eval_core

Check that metrics.json is written and test_nll is available: true.

Optional Tests (by Claimed Capability)

Sampling

def test_predict_next(tiny_train, tiny_val, tiny_test):
    model = STPPEstimator("my_preset", device="cpu")
    model.fit(tiny_train, tiny_val, tiny_test, epochs=1, batch_size=2)

    samples = model.predict_next(tiny_test[:1], n_samples=4)
    assert "next_times" in samples
    assert "next_locations" in samples

Surface diagnostics

python -m seahorse evaluate surface \
  --run runs/test_my_preset/fit/my_preset/<run_id> \
  --history data/tiny/test.jsonl \
  --split test \
  --seq-idx 0 \
  --profile history_frame \
  --out runs/test_my_preset/surface

What NOT to Test Here

  • Training convergence on real data — that belongs in an experiment script, not in the test suite.
  • Numerical equivalence with a reference implementation — add a separate regression test if needed.
  • Speed or memory — benchmark these separately before claiming production-readiness.

Conftest Helpers

Add a conftest.py that generates tiny synthetic sequences:

import json
import pytest

@pytest.fixture
def tiny_train(tmp_path):
    path = tmp_path / "train.jsonl"
    with open(path, "w") as f:
        for _ in range(5):
            seq = {
                "times": [0.1, 0.3, 0.6, 0.9],
                "locations": [[0.1, 0.2], [0.4, 0.5], [0.6, 0.3], [0.8, 0.7]],
            }
            f.write(json.dumps(seq) + "\n")
    from seahorse import load_jsonl
    return load_jsonl(str(path))

Mirror this for tiny_val and tiny_test.