-
Notifications
You must be signed in to change notification settings - Fork 0
Testing
Signal has a full unit test suite covering all pipeline modules including Pass 6 (weekly) and Pass 7 (monthly). All tests run offline — LLM calls and network I/O are mocked, so the suite completes in under two minutes with no external dependencies.
From the repo root:
.venv/bin/python -m pytestCoverage is printed to the terminal and written as HTML to htmlcov/. Open htmlcov/index.html in a browser for a line-by-line view.
# Run a single file
.venv/bin/python -m pytest tests/test_store.py
# Run a single test
.venv/bin/python -m pytest tests/test_store.py::TestRuns::test_finish_run
# Skip coverage for faster feedback
.venv/bin/python -m pytest --no-cov| File | What it tests |
|---|---|
tests/conftest.py |
Shared fixtures used by all test files |
tests/test_store.py |
SQLite persistence layer (pipeline/store.py) |
tests/test_collector.py |
Feed collection and article normalization (pipeline/collector.py) |
tests/test_analyzer.py |
All five analysis passes, LLM dispatch, clustering (pipeline/analyzer.py) |
tests/test_reporter.py |
HTML report generation, GA snippet, markdown rendering (pipeline/reporter.py) |
tests/test_weekly.py |
Pass 6 weekly synthesis logic (pipeline/weekly.py) |
tests/test_monthly.py |
Pass 7 monthly synthesis logic (pipeline/monthly.py) |
| Module | Coverage | Notes |
|---|---|---|
analyzer.py |
100% | All passes, helpers, LLM dispatch, and error paths |
store.py |
94% | Remaining gaps are error-path JSON decode branches |
collector.py |
92% | Missing: load_config() (reads real YAML), minor _fetch_full_text edge cases |
weekly.py |
86% | Ollama provider branch intentionally untested — Ollama is disabled in scheduled runs |
monthly.py |
98% | Pass 7 synthesis, partial month detection, DB persistence |
reporter.py |
84% | Daily, weekly, and monthly HTML template helpers |
| Overall | ~93% | 239 tests |
All LLM calls are mocked. Tests never invoke Claude or Ollama. The mock targets the _llm_call function inside the module under test:
@patch("pipeline.analyzer._llm_call")
def test_something(self, mock_llm, mock_entity_response):
mock_llm.return_value = mock_entity_responseDatabase isolation. The tmp_db fixture patches store.DB_PATH to a temporary file scoped to each test. Tests never touch signal.db.
File system isolation. Reporter tests patch pipeline.reporter.REPORTS_DIR with tmp_path. No files are ever written to the real reports/ directory during a test run.
- Add cases to the relevant existing file, or create
tests/test_<module>.pyfor a new module. - Use
make_article()fromconftest.pyto build article fixtures — don't hand-craft dicts inline. - Mock external I/O at the lowest boundary: LLM → patch
_llm_call; HTTP → patchhttpx.getorfeedparser.parse; DB → usetmp_db; file writes → patch*_DIRwithtmp_path. - Group related cases into a class (e.g.
class TestRuns:) for readable output. - Verify with
pytest --no-cov, then confirm coverage didn't regress withpytest.
For full details on fixtures and conventions, see tests/README.md in the repository.
Signal · Repository · fleXRPL · Daily political intelligence — powered by local AI