Testing Strategy

Testing patterns and coverage goals

2 min read 409 words

Bengal maintains high code quality through a multi-layered testing strategy with 4,000+ tests.

Test Layers

Unit Tests

Fast & Focused (tests/unit/) Test individual classes/functions. Mock external deps. Target: 90%+ coverage.

Integration Tests

Workflows (tests/integration/) Test subsystem interactions and build flows. Verify cache.

Benchmarks

Performance (benchmarks/) Measure build speed, memory, incremental builds. Entry points:test_build.py, test_cold_build_permutations.py, test_nav_tree_performance.py.

Quick Start

# Fast feedback loop (recommended during development)
pytest -m "not slow" -n auto  # ~20 seconds

# Unit tests only
pytest tests/unit -n auto  # ~8 seconds

# Full suite
pytest  # ~60 seconds

Test Infrastructure

Test Roots

Minimal, reusable site structures intests/roots/:

Root Purpose Pages
test-basic Minimal smoke test 1
test-directives Card, admonition, glossary 4+
test-navigation Multi-level hierarchy 8
test-large Performance testing 100+
@pytest.mark.bengal(testroot="test-directives")
def test_card_directive(site, build_site):
    build_site()
    assert "card-grid" in (site.output_dir / "cards/index.html").read_text()

Canonical Mocks

Use shared mocks instead of inline class definitions:

from tests._testing.mocks import MockPage, MockSection, MockSite

page = MockPage(title="Test", url="/test/", tags=["python"])
site = MockSite(pages=[page])

Module-Scoped Fixtures

Rendering tests use module-scoped parser for efficiency:

# In tests/unit/rendering/
def test_markdown(parser):  # Parser created once per module
    result = parser.parse("# Hello", {})
    assert "<h1>" in result

Key Testing Patterns

1. Declarative Test Sites

@pytest.mark.bengal(testroot="test-basic", confoverrides={"site.title": "Custom"})
def test_with_overrides(site):
    assert site.title == "Custom"

2. Property-Based Testing

For critical utilities, we usehypothesisto test edge cases (116 tests, 11,600+ examples).

3. Parallel Safety

Mark tests with internal parallelism:

@pytest.mark.parallel_unsafe  # Prevents xdist worker crashes
def test_concurrent_operations():
    with ThreadPoolExecutor() as ex:
        ...

Incremental Build Invariants

Incremental behavior is verified with invariant tests that exercise real build flows without mocks. Seetests/integration/test_incremental_invariants.pyfor:

  • Unchanged builds skip all pages
  • Single-page content edits rebuild only that page
  • Section updates propagate to parents
  • Cross-process cache stability

These tests protect the provenance-based detection pipeline from regressions and should be updated alongside changes to incremental build logic.

Continuous Integration

Every PR runs:

  1. Linting:ruffcheck and format
  2. Type Checking:tytype checker
  3. Test Suite: Unit + integration (-m "not slow")
  4. Full Suite: On main/release branches

Seetests/README.mdfor complete documentation.