102 lines
3.2 KiB
Markdown
102 lines
3.2 KiB
Markdown
---
|
|
title: Testing
|
|
sidebar_position: 7
|
|
---
|
|
|
|
# Testing
|
|
|
|
## Running Tests
|
|
|
|
All tests must run inside containers:
|
|
|
|
```bash
|
|
# Unit tests (default: excludes integration markers)
|
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm app \
|
|
python -m pytest
|
|
|
|
# Integration tests
|
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm app \
|
|
python -m pytest -m integration
|
|
|
|
# Specific marker
|
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm app \
|
|
python -m pytest -m db
|
|
|
|
# Verbose output for a specific file
|
|
docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm app \
|
|
python -m pytest tests/unit/test_fingerprints.py -v
|
|
```
|
|
|
|
## Test Configuration
|
|
|
|
From `pyproject.toml`:
|
|
|
|
```toml
|
|
[tool.pytest.ini_options]
|
|
addopts = "-q -m \"not integration\" --import-mode=importlib"
|
|
asyncio_mode = "auto"
|
|
testpaths = ["tests"]
|
|
```
|
|
|
|
- Default run excludes `integration` marked tests
|
|
- Uses `importlib` import mode to resolve module name collisions
|
|
- Async tests run automatically (no `@pytest.mark.asyncio` needed)
|
|
|
|
## Markers
|
|
|
|
| Marker | Description |
|
|
|--------|-------------|
|
|
| `integration` | Tests requiring external services (database, network) |
|
|
| `db` | Tests that validate database behavior and constraints |
|
|
| `migrations` | Tests focused on Alembic schema migration correctness |
|
|
| `schema` | Tests focused on multi-tenant schema invariants |
|
|
| `smoke` | Smoke tests for containerized runtime |
|
|
|
|
## Test Tiers
|
|
|
|
### Unit Tests (`tests/unit/`)
|
|
|
|
Fast, no-database tests. Mock external dependencies. These run by default.
|
|
|
|
Examples:
|
|
- `test_fingerprints.py` - Publication fingerprinting logic
|
|
- `test_scholar_parser.py` - HTML parsing without network calls
|
|
- `test_doi_normalize.py` - DOI normalization rules
|
|
- `test_ingestion_arxiv_rate_limit.py` - Rate limiter behavior
|
|
- `test_publication_pdf_resolution_pipeline.py` - PDF pipeline logic
|
|
|
|
Domain-specific unit tests are organized under `tests/unit/services/domains/`:
|
|
- `arxiv/` - Cache, client, gateway, guards, parser, rate limit tests
|
|
- `openalex/` - Client and matching tests
|
|
- `publications/` - Dedup tests
|
|
|
|
### Integration Tests (`tests/integration/`)
|
|
|
|
Require a running database. Test full request/response flows and data consistency.
|
|
|
|
Examples:
|
|
- `test_api_v1.py` - API endpoint integration tests
|
|
- `test_db_integrity.py` - Database integrity checks
|
|
- `test_run_lifecycle_consistency.py` - Run state machine transitions
|
|
- `test_deferred_enrichment.py` - Enrichment pipeline with real data
|
|
- `test_fixture_probe_runs.py` - Fixture-based run probes
|
|
|
|
### Smoke Tests
|
|
|
|
Marked with `@pytest.mark.smoke`. Validate the containerized runtime starts and serves basic requests.
|
|
|
|
## Fixtures
|
|
|
|
Test fixtures live in `tests/fixtures/`:
|
|
|
|
```
|
|
tests/fixtures/
|
|
└── scholar/
|
|
├── profile_ok_amIMrIEAAAAJ.html # Successful profile HTML
|
|
└── regression/
|
|
├── profile_P1RwlvoAAAAJ.html # Regression case
|
|
├── profile_LZ5D_p4AAAAJ.html # Regression case
|
|
└── profile_AAAAAAAAAAAA.html # Regression case
|
|
```
|
|
|
|
Scholar HTML fixtures are real Google Scholar profile pages used to test parser robustness against DOM structure changes.
|