Testing Guide

This guide covers testing practices and methodologies used in Tessera development.

Test Structure

The test suite is organized into three main categories:

tests/
├── fixtures/       # Shared test fixtures and utilities
├── integration/    # End-to-end and integration tests
└── unit/          # Unit tests for individual components

Testing Tools

Tessera uses these testing tools:

  • pytest: Main testing framework

  • pytest-cov: Code coverage reporting

  • pytest-asyncio: Async test support

  • hypothesis: Property-based testing

Running Tests

Basic Usage:

# Run all tests
pytest

# Run with verbose output
pytest -v

# Run specific test file
pytest tests/unit/test_state.py

# Run specific test function
pytest tests/unit/test_state.py::test_state_transition

Coverage Reports:

# Generate coverage report
pytest --cov=jam

# Generate HTML report
pytest --cov=jam --cov-report=html

# View report in browser
open htmlcov/index.html

Writing Tests

  1. Unit Tests:

    # tests/unit/test_feature.py
    import pytest
    from jam.feature import Feature
    
    def test_feature_behavior():
        # Arrange
        feature = Feature()
    
        # Act
        result = feature.process()
    
        # Assert
        assert result == expected
    
  2. Integration Tests:

    # tests/integration/test_workflow.py
    import pytest
    from jam.workflow import Workflow
    
    @pytest.mark.asyncio
    async def test_end_to_end():
        # Setup
        workflow = Workflow()
    
        # Execute
        result = await workflow.run()
    
        # Verify
        assert result.status == "success"
    

Using Fixtures

  1. Create Fixtures:

    # tests/fixtures/conftest.py
    import pytest
    
    @pytest.fixture
    def test_data():
        return {
            "key": "value"
        }
    
    @pytest.fixture
    async def async_resource():
        resource = await setup_resource()
        yield resource
        await cleanup_resource()
    
  2. Use Fixtures:

    # tests/unit/test_feature.py
    def test_with_fixture(test_data):
        assert process(test_data) == expected
    
    @pytest.mark.asyncio
    async def test_async(async_resource):
        result = await async_resource.query()
        assert result
    

Property-Based Testing

Using Hypothesis:

from hypothesis import given, strategies as st

@given(st.integers(), st.integers())
def test_addition_properties(x, y):
    result = add(x, y)
    assert result == add(y, x)  # Commutative
    assert add(result, 0) == result  # Identity

Mocking

Using pytest-mock:

def test_with_mock(mocker):
    # Create mock
    mock_db = mocker.patch('jam.database.Database')
    mock_db.query.return_value = expected_result

    # Use mock
    result = process_data()

    # Verify
    mock_db.query.assert_called_once()
    assert result == expected_result

Best Practices

  1. Test Organization: * One test file per module * Clear test names describing behavior * Group related tests in classes

  2. Test Design: * Follow Arrange-Act-Assert pattern * Test edge cases and error conditions * Keep tests focused and isolated

  3. Fixtures: * Use fixtures for common setup * Clean up resources properly * Share fixtures via conftest.py

  4. Coverage: * Aim for high test coverage * Focus on critical paths * Don’t sacrifice quality for coverage

  5. Performance: * Keep tests fast * Use async testing where appropriate * Minimize external dependencies