CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-green

Green is a clean, colorful, fast python test runner.

Pending
Overview
Eval results
Files

test-execution.mddocs/

Test Execution

Green's test execution system provides multi-process parallel test running with process pool management, worker initialization, and comprehensive test orchestration for improved performance.

Capabilities

Main Test Runner

The core function that orchestrates test execution with Green's enhanced features including parallel processing, coverage integration, and result aggregation.

def run(suite, stream, args, testing=False):
    """
    Run tests with Green's enhanced features.
    
    Args:
        suite: Test suite to run (GreenTestSuite or unittest.TestSuite)
        stream: Output stream, will be wrapped in GreenStream if not already
        args: Configuration namespace containing execution parameters:
              - processes: Number of parallel processes (0 = auto-detect)
              - run_coverage: Enable coverage reporting
              - initializer: Worker process initializer function
              - finalizer: Worker process finalizer function  
              - debug: Debug level for execution details
        testing (bool): Enable testing mode behavior (affects coverage and output)
    
    Returns:
        GreenTestResult: Comprehensive test execution results with:
                        - Individual test outcomes
                        - Timing information
                        - Coverage data (if enabled)
                        - Process execution statistics
    
    Example:
        from green.runner import run
        from green.loader import GreenTestLoader
        from green.output import GreenStream
        from green.config import get_default_args
        import sys
        
        # Load tests
        loader = GreenTestLoader()
        suite = loader.loadTargets(['tests/'])
        
        # Configure execution
        args = get_default_args()
        args.processes = 4
        args.run_coverage = True
        
        # Run tests
        stream = GreenStream(sys.stdout)
        result = run(suite, stream, args)
        
        print(f"Tests run: {result.testsRun}")
        print(f"Success: {result.wasSuccessful()}")
    """

Worker Process Management

Helper class for managing worker process initialization and cleanup functions.

class InitializerOrFinalizer:
    """
    Manages worker process setup and teardown functions.
    
    Allows specifying custom initialization and cleanup code that runs
    in each worker process before and after test execution.
    """
    
    def __init__(self, dotted_function):
        """
        Initialize with a dotted function name.
        
        Args:
            dotted_function (str): Fully qualified function name like
                                  'mymodule.setup_function' or 
                                  'mypackage.tests.init_worker'
        
        Example:
            initializer = InitializerOrFinalizer('tests.setup.init_database')
            finalizer = InitializerOrFinalizer('tests.setup.cleanup_database')
        """
    
    def __call__(self, *args):
        """
        Execute the configured function.
        
        Args:
            *args: Arguments to pass to the function
        
        Raises:
            InitializerOrFinalizerError: If function cannot be loaded or executed
        """

Usage Examples

Basic Test Execution

from green.runner import run
from green.loader import GreenTestLoader  
from green.output import GreenStream
from green.config import parseArguments, mergeConfig
import sys

# Load and configure
args = parseArguments(['tests/'])
config = mergeConfig(args)

loader = GreenTestLoader()
suite = loader.loadTargets(config.targets)

# Execute tests
stream = GreenStream(sys.stdout)
result = run(suite, stream, config)

# Check results
if result.wasSuccessful():
    print("All tests passed!")
    exit(0)  
else:
    print(f"Tests failed: {len(result.failures)} failures, {len(result.errors)} errors")
    exit(1)

Parallel Execution Configuration

from green.runner import run
from green.config import get_default_args

# Configure parallel execution
args = get_default_args()
args.processes = 8  # Use 8 processes
args.debug = 1      # Enable debug output

# Auto-detect optimal process count
args.processes = 0  # Green will use multiprocessing.cpu_count()

# Single-process execution (useful for debugging)
args.processes = 1

Custom Worker Initialization

from green.runner import run, InitializerOrFinalizer
from green.config import get_default_args

# Create worker setup functions
def setup_test_database():
    """Initialize test database connection in worker process."""
    import sqlite3
    global db_connection
    db_connection = sqlite3.connect(':memory:')
    # Setup test tables, etc.

def cleanup_test_database():
    """Clean up test database in worker process."""
    global db_connection
    if db_connection:
        db_connection.close()

# Configure with initializer/finalizer
args = get_default_args()
args.initializer = 'tests.setup.setup_test_database'
args.finalizer = 'tests.setup.cleanup_test_database'

# The InitializerOrFinalizer will be used internally
result = run(suite, stream, args)

Coverage Integration

from green.runner import run
from green.config import get_default_args

# Enable coverage
args = get_default_args()
args.run_coverage = True
args.coverage_config_file = '.coveragerc'  # Custom coverage config
args.omit_patterns = ['*/tests/*', '*/venv/*']  # Patterns to omit

result = run(suite, stream, args)

# Coverage data will be automatically collected and reported

Debug Mode Execution

from green.runner import run
from green.config import get_default_args

# Enable detailed debug output
args = get_default_args()
args.debug = 2  # Higher debug levels provide more detail
args.processes = 1  # Single process for easier debugging

result = run(suite, stream, args)

Error Handling and Recovery

from green.runner import run
from green.exceptions import InitializerOrFinalizerError

try:
    result = run(suite, stream, args)
    
    # Check for various error conditions
    if result.errors:
        print(f"Test errors occurred: {len(result.errors)}")
        for test, error in result.errors:
            print(f"  {test}: {error}")
    
    if result.failures:
        print(f"Test failures occurred: {len(result.failures)}")
        for test, failure in result.failures:
            print(f"  {test}: {failure}")
            
except InitializerOrFinalizerError as e:
    print(f"Worker process setup failed: {e}")
    # Handle worker initialization errors
    
except KeyboardInterrupt:
    print("Test execution interrupted by user")
    # Handle Ctrl+C gracefully
    
except Exception as e:
    print(f"Unexpected error during test execution: {e}")
    # Handle other execution errors

Advanced Execution Scenarios

from green.runner import run
from green.suite import GreenTestSuite
from green.config import get_default_args

# Custom test suite configuration
suite = GreenTestSuite()
# Add tests to suite...

# Configure for specific execution environment
args = get_default_args()

# CI/CD environment
if os.environ.get('CI'):
    args.processes = 0  # Auto-detect
    args.run_coverage = True
    args.junit_report = 'test-results.xml'
    args.verbose = 1  # Minimal output for CI logs

# Development environment  
else:
    args.processes = 2  # Don't overwhelm development machine
    args.verbose = 2   # More verbose for development
    args.debug = 1     # Enable debug output

result = run(suite, stream, args)

Integration with Custom Test Frameworks

from green.runner import run
from green.loader import GreenTestLoader
import unittest

class CustomTestResult(unittest.TestResult):
    """Custom result processor."""
    pass

# Green can work with custom test frameworks
loader = GreenTestLoader()
suite = loader.loadTargets(['tests/'])

# Green will handle the parallel execution and result aggregation
result = run(suite, stream, args)

# Post-process results with custom logic
custom_processor = CustomTestResult()
# Process results as needed...

Process Pool Management

Green uses a custom process pool implementation for enhanced parallel execution:

Features

  • Daemonless Processes: Workers can spawn their own subprocesses
  • Custom Finalizers: Clean shutdown of worker processes
  • Enhanced Logging: Better error reporting from worker processes
  • Coverage Integration: Automatic coverage data collection from workers
  • Signal Handling: Graceful handling of interruption signals

Configuration Options

# Process count options
args.processes = 0    # Auto-detect (multiprocessing.cpu_count())
args.processes = 1    # Single process (no parallelization)
args.processes = 4    # Specific process count
args.processes = -1   # Use all available CPUs

# Worker customization
args.initializer = 'module.setup_function'    # Run in each worker on startup
args.finalizer = 'module.cleanup_function'    # Run in each worker on shutdown

Performance Considerations

Optimal Process Count

  • CPU-bound tests: processes = cpu_count()
  • I/O-bound tests: processes = cpu_count() * 2
  • Memory-intensive tests: processes = cpu_count() / 2
  • Development/debugging: processes = 1

Test Organization for Parallelization

  • Group related tests in the same module
  • Avoid shared state between test methods
  • Use fixtures for test data setup/teardown
  • Consider process-local resources (databases, files)

Coverage Overhead

  • Coverage adds ~20-30% execution time
  • Benefits from parallel execution
  • Use .coveragerc to optimize data collection
  • Consider coverage sampling for very large test suites

Install with Tessl CLI

npx tessl i tessl/pypi-green

docs

cli.md

configuration.md

django-integration.md

index.md

junit-xml.md

output-formatting.md

setuptools-integration.md

test-execution.md

test-loading.md

test-results.md

tile.json