# Testing Guide This document provides comprehensive guidelines for testing the MarkiTect project. ## Overview MarkiTect uses a multi-layered testing approach with pytest as the primary testing framework. Our testing strategy ensures code quality, reliability, and maintainability across all components. ## Testing Framework - **Primary Framework**: pytest - **Configuration**: `pytest.ini` - **Test Directory**: `tests/` - **Python Versions**: 3.8+ ## Test Structure ``` tests/ ├── conftest.py # Shared test configuration and fixtures ├── e2e/ # End-to-end tests ├── fixtures/ # Test data and fixtures ├── integration/ # Integration tests ├── unit/ # Unit tests (by component) ├── test_*.py # Individual test modules └── __pycache__/ # Python cache (auto-generated) ``` ## Running Tests ### Quick Start ```bash # Run all tests pytest # Run tests with verbose output pytest -v # Run specific test file pytest tests/test_cli.py # Run tests matching pattern pytest -k "test_database" # Run with coverage pytest --cov=markitect --cov-report=html ``` ### Test Categories #### Unit Tests ```bash # Run unit tests only pytest tests/unit/ # Example: Test specific component pytest tests/test_database.py pytest tests/test_template_engine.py ``` #### Integration Tests ```bash # Run integration tests pytest tests/integration/ # Example: Test CLI integration pytest tests/test_cli_integration.py ``` #### End-to-End Tests ```bash # Run E2E tests pytest tests/e2e/ ``` ## Test Configuration ### pytest.ini Configuration - **Strict markers**: Enforces defined test markers - **Verbose output**: Detailed test results - **Duration tracking**: Shows slowest 10 tests - **Fail fast**: Stops after 3 failures ### Custom Markers ```bash # Performance tests pytest -m performance # Slow tests (run separately) pytest -m slow # Database tests pytest -m database ``` ## Writing Tests ### Test Naming Conventions - Test files: `test_*.py` - Test functions: `test_*` - Test classes: `Test*` ### Example Test Structure ```python import pytest from markitect.core import MarkiTect class TestMarkiTect: """Test suite for core MarkiTect functionality.""" def test_basic_functionality(self): """Test basic operation.""" # Arrange markitect = MarkiTect() # Act result = markitect.process("# Test") # Assert assert result is not None @pytest.mark.slow def test_performance_intensive(self): """Test that requires significant time.""" pass ``` ### Fixtures and Test Data ```python # conftest.py @pytest.fixture def sample_markdown(): """Provide sample markdown for testing.""" return "# Sample\n\nTest content" @pytest.fixture def temp_database(): """Provide temporary test database.""" # Setup db = create_test_db() yield db # Cleanup db.close() ``` ## Test Types and Guidelines ### Unit Tests - **Scope**: Single function/method - **Dependencies**: Mocked/isolated - **Speed**: Fast (<100ms) - **Location**: `tests/unit/` ### Integration Tests - **Scope**: Component interaction - **Dependencies**: Real dependencies within system - **Speed**: Medium (100ms-2s) - **Location**: `tests/integration/` ### End-to-End Tests - **Scope**: Full system workflows - **Dependencies**: Complete system - **Speed**: Slow (>2s) - **Location**: `tests/e2e/` ## Performance Testing ### Benchmarking ```bash # Run performance benchmarks markitect perf-benchmark --test-type all # Validate performance thresholds markitect perf-validate --threshold-ops 100 ``` ### Performance Tests in pytest ```python @pytest.mark.performance def test_large_document_processing(): """Ensure large documents process within time limits.""" start_time = time.time() # ... test logic ... duration = time.time() - start_time assert duration < 5.0 # Max 5 seconds ``` ## Database Testing ### Test Database Setup - Uses temporary SQLite databases - Automatic cleanup after tests - Isolated transactions per test ```python @pytest.fixture def test_db(): """Provide isolated test database.""" from markitect.database import DatabaseManager db = DatabaseManager(":memory:") # In-memory database yield db db.close() ``` ## CLI Testing ### Testing CLI Commands ```python from click.testing import CliRunner from markitect.cli import cli def test_cli_help(): """Test CLI help command.""" runner = CliRunner() result = runner.invoke(cli, ['--help']) assert result.exit_code == 0 assert 'MarkiTect' in result.output ``` ## Continuous Integration ### GitHub Actions - Automatic test execution on push/PR - Multiple Python versions tested - Coverage reports generated - Configuration: `.github/workflows/test.yml` ### Quality Gates - All tests must pass - Coverage minimum: 80% - No failing static analysis checks ## Test Data Management ### Fixtures Directory ``` tests/fixtures/ ├── sample_documents/ # Test markdown files ├── expected_outputs/ # Expected test results ├── schemas/ # Test schemas └── data/ # Test data files ``` ### Test Data Guidelines - Keep test data minimal but representative - Use meaningful names - Include edge cases - Document complex test scenarios ## Debugging Tests ### Common Debugging Commands ```bash # Run single test with detailed output pytest tests/test_module.py::test_function -vvv # Drop into debugger on failure pytest --pdb # Stop on first failure pytest -x # Show local variables in tracebacks pytest --tb=long -l ``` ### Logging in Tests ```python import logging import pytest def test_with_logging(caplog): """Test that captures log output.""" with caplog.at_level(logging.INFO): # ... test code that logs ... assert "Expected message" in caplog.text ``` ## Best Practices ### Test Organization 1. **One concept per test**: Each test should verify one specific behavior 2. **Clear naming**: Test names should describe what is being tested 3. **Arrange-Act-Assert**: Structure tests clearly 4. **Independent tests**: Tests should not depend on each other ### Test Maintenance 1. **Keep tests simple**: Complex tests are hard to maintain 2. **Regular cleanup**: Remove obsolete tests 3. **Update documentation**: Keep this guide current 4. **Review coverage**: Aim for high but meaningful coverage ### Performance Considerations 1. **Fast feedback**: Unit tests should be very fast 2. **Parallel execution**: Tests should support parallel running 3. **Resource cleanup**: Always clean up resources 4. **Mocking**: Mock external dependencies appropriately ## Troubleshooting ### Common Issues #### Import Errors ```bash # Ensure PYTHONPATH is set correctly export PYTHONPATH=. pytest ``` #### Database Conflicts ```bash # Clean test database rm -f test_markitect.db pytest ``` #### Slow Tests ```bash # Profile test execution pytest --durations=0 ``` ## Contributing When contributing tests: 1. **Follow naming conventions** 2. **Add appropriate markers** 3. **Include docstrings** 4. **Test edge cases** 5. **Update this documentation if needed** For more information about contributing, see the project's contribution guidelines. ## Resources - [pytest Documentation](https://docs.pytest.org/) - [Python Testing Best Practices](https://realpython.com/python-testing/) - [Project Architecture Documentation](docs/architecture/) - [Development Guidelines](docs/development/)