|
| 1 | +# Test Infrastructure |
| 2 | + |
| 3 | +The test suite is built with Pytest and is designed around isolation. Tests avoid writing into the real home directory, avoid live NBER network calls, and cover both CLI and library behavior. |
| 4 | + |
| 5 | +## Run Tests |
| 6 | + |
| 7 | +```bash |
| 8 | +uv run pytest |
| 9 | +uv run pytest tests/test_cli.py |
| 10 | +uv run pytest -m "not slow" |
| 11 | +``` |
| 12 | + |
| 13 | +Run linting and documentation checks with: |
| 14 | + |
| 15 | +```bash |
| 16 | +uv run ruff check . |
| 17 | +uv run --group docs mkdocs build --strict |
| 18 | +``` |
| 19 | + |
| 20 | +## Test Suite Map |
| 21 | + |
| 22 | +| Area | Representative files | What it covers | |
| 23 | +| --- | --- | --- | |
| 24 | +| CLI | `tests/test_cli.py`, `tests/test_main.py` | Argument parsing, subcommand behavior, output formats, exit behavior. | |
| 25 | +| Network fetcher | `tests/test_fetcher.py` | Paper page parsing, search payload parsing, retry and request behavior. | |
| 26 | +| Downloads | `tests/test_downloader.py` | Single and batch download paths, validation, failures, concurrency behavior. | |
| 27 | +| Feed | `tests/test_feed.py` | RSS parsing, malformed XML handling, new-item detection, cleanup. | |
| 28 | +| Database | `tests/test_db.py`, `tests/test_config_store.py` | Schema creation, config persistence, migration, path normalization, cache tables. | |
| 29 | +| Info cache | `tests/test_info_cache.py`, `tests/test_info_cache_flow.py` | Cache hits, refresh behavior, TTL logic, integration with `info`. | |
| 30 | +| MCP | `tests/test_mcp.py` | Tool return shapes, error handling, paper ID normalization, download path restrictions. | |
| 31 | +| Logging | `tests/test_logging.py`, `tests/test_logs.py` | Log configuration, debug behavior, rotating file setup. | |
| 32 | + |
| 33 | +## Isolation Model |
| 34 | + |
| 35 | +The global fixture in `tests/conftest.py` redirects the NBER-CLI home directory behavior into a temporary path. This protects the user's real `~/.nber-cli/config.json`, database, and debug log during test runs. |
| 36 | + |
| 37 | +Tests patch `Path.home()`, database paths, network functions, and HTTP sessions as needed. The goal is that a test can be run repeatedly without depending on the developer's machine state or network access. |
| 38 | + |
| 39 | +```mermaid |
| 40 | +flowchart LR |
| 41 | + pytest[Pytest] --> fixture[isolated_nber_home] |
| 42 | + fixture --> temp[temporary home] |
| 43 | + temp --> config[config.json] |
| 44 | + temp --> database[nber.db] |
| 45 | + pytest --> mocks[network and session mocks] |
| 46 | + mocks --> fetcher[fetcher.py] |
| 47 | + mocks --> download[download.py] |
| 48 | + mocks --> feed[feed.py] |
| 49 | +``` |
| 50 | + |
| 51 | +## Mocking Strategy |
| 52 | + |
| 53 | +Network-facing tests mock the lowest practical boundary: |
| 54 | + |
| 55 | +- Synchronous page and feed retrieval patch `_load_text_sync` or `urllib.request.urlopen`. |
| 56 | +- Async search and download paths use fake `aiohttp` sessions or async mocks. |
| 57 | +- CLI tests patch high-level functions when the test is about argument dispatch rather than parsing NBER responses. |
| 58 | + |
| 59 | +This split keeps parser tests focused on parsing, command tests focused on CLI behavior, and integration-style tests focused on component interaction. |
| 60 | + |
| 61 | +## Async Patterns |
| 62 | + |
| 63 | +Async functions are tested through `pytest-asyncio` or by invoking CLI paths that internally call `asyncio.run`. Download batch tests assert both successful paths and collected failures because `download_multiple_papers` returns a `DownloadBatchResult` instead of raising when individual downloads fail. |
| 64 | + |
| 65 | +## Robustness Coverage |
| 66 | + |
| 67 | +The tests intentionally cover edge cases that are easy to break: |
| 68 | + |
| 69 | +- Paper IDs with and without the `w` prefix. |
| 70 | +- Invalid paper IDs and mismatched fetched paper IDs. |
| 71 | +- Search pagination limits and date defaults. |
| 72 | +- XML entities and malformed RSS text. |
| 73 | +- Database schema upgrades and future-schema rejection. |
| 74 | +- Download path restrictions for CLI and MCP surfaces. |
| 75 | +- Cache refresh, sliding TTL, and cleanup date ranges. |
| 76 | + |
| 77 | +## Adding Tests |
| 78 | + |
| 79 | +When changing user-visible behavior, add tests at the surface where the behavior is observed. For example, add CLI tests for command output and exit behavior, MCP tests for tool return shapes, and lower-level tests for parser or database helpers. |
| 80 | + |
| 81 | +Keep fixtures local to a test file unless they are reused broadly. If a fixture touches home directories, database files, network calls, or environment variables, make sure it restores state automatically. |
0 commit comments