Skip to content

Comprehensive Testing Framework & Test Coverage

Overview

Establish a comprehensive testing framework that ensures all MCP tools work correctly and reliably for Claude agents. This includes unit tests, integration tests, end-to-end tests, and performance tests that validate the entire system.

Claude Agent Success Criteria

A Claude agent should be able to:

  • Run all tests and get clear pass/fail results
  • Understand test failures with actionable error messages
  • Add new tests when implementing features
  • Validate system reliability through comprehensive test coverage

Detailed Acceptance Criteria

1. Test Framework Setup

Configure comprehensive testing infrastructure:

{
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run",
    "test:coverage": "vitest run --coverage",
    "test:coverage:ci": "vitest run --coverage --reporter=junit --reporter=json --reporter=verbose",
    "test:unit": "vitest run tests/unit",
    "test:integration": "vitest run tests/integration", 
    "test:e2e": "vitest run tests/e2e",
    "test:performance": "vitest run tests/performance",
    "coverage:check": "vitest run --coverage && node scripts/check-coverage.js",
    "coverage:report": "vitest run --coverage && open coverage/index.html"
  }
}

Test Structure:

  • tests/unit/ - Unit tests for individual functions and components

  • tests/integration/ - Integration tests with real databases and CLI

  • tests/e2e/ - End-to-end workflow tests

  • tests/performance/ - Performance and load tests

  • tests/fixtures/ - Test data, configurations, and mock databases

  • Configure Vitest with TypeScript support

  • Set up test coverage reporting (≥80% required)

  • Create test database setup and teardown utilities

  • Implement test fixtures and mock data

  • Add performance testing capabilities

2. Unit Test Suite

Comprehensive unit tests for all core functionality:

Core Utilities Tests:

// tests/unit/graphile-migrate/executor.test.ts
describe('GraphileMigrateExecutor', () => {
  test('executes commands correctly', async () => {
    const executor = new GraphileMigrateExecutor();
    const result = await executor.execute('status', [], { workingDirectory: testDir });
    expect(result.success).toBe(true);
  });

  test('handles command failures gracefully', async () => {
    const executor = new GraphileMigrateExecutor();
    const result = await executor.execute('invalid-command', [], { workingDirectory: testDir });
    expect(result.success).toBe(false);
    expect(result.stderr).toContain('Unknown command');
  });
});

MCP Tools Tests:

// tests/unit/tools/migration-status.test.ts
describe('get_migration_status tool', () => {
  test('returns comprehensive status for valid project', async () => {
    const result = await getMigrationStatus({ projectPath: testProjectPath });
    expect(result.success).toBe(true);
    expect(result.data.project.configValid).toBe(true);
    expect(result.data.committed).toBeArrayOf(expect.objectContaining({
      filename: expect.any(String),
      path: expect.any(String)
    }));
  });
});
  • Test all MCP tools with valid inputs
  • Test error handling and edge cases
  • Test validation logic and pattern detection
  • Test file operations and I/O
  • Test utility functions and helpers

3. Integration Test Suite

Integration tests with real databases and systems:

Database Integration Tests:

// tests/integration/database.test.ts
describe('Database Integration', () => {
  let testDb: TestDatabase;

  beforeEach(async () => {
    testDb = await createTestDatabase();
  });

  afterEach(async () => {
    await testDb.cleanup();
  });

  test('schema analysis returns accurate results', async () => {
    await testDb.executeSql('CREATE TABLE users (id SERIAL PRIMARY KEY)');
    const analysis = await analyzeSchema({ projectPath: testDb.projectPath });
    expect(analysis.data.tables).toHaveLength(1);
    expect(analysis.data.tables[0].name).toBe('users');
  });
});

CLI Integration Tests:

// tests/integration/cli.test.ts
describe('Graphile Migrate CLI Integration', () => {
  test('executes real migration commands', async () => {
    const project = await createTestProject();
    const result = await executeCommand('migrate', [], { workingDirectory: project.path });
    expect(result.exitCode).toBe(0);
  });
});
  • Test with real PostgreSQL databases
  • Test actual Graphile Migrate CLI integration
  • Test file system operations
  • Test network operations and timeouts
  • Test multi-database scenarios

4. End-to-End Test Suite

Complete workflow tests simulating real usage:

Developer Workflow Tests:

// tests/e2e/developer-workflow.test.ts
describe('Complete Developer Workflow', () => {
  test('full migration development cycle', async () => {
    const project = await setupTestProject();
    
    // 1. Create new migration
    const created = await createMigration({
      projectPath: project.path,
      migrationName: 'add_users_table',
      template: 'table'
    });
    expect(created.success).toBe(true);
    
    // 2. Validate migration
    const validation = await analyzeMigrationSafety({
      projectPath: project.path
    });
    expect(validation.data.idempotency.score).toBeGreaterThan(80);
    
    // 3. Test idempotency
    const idempotency = await testMigrationIdempotency({
      projectPath: project.path,
      iterations: 3
    });
    expect(idempotency.data.test.passed).toBe(true);
    
    // 4. Commit migration
    const commit = await commitMigration({
      projectPath: project.path,
      message: 'Add users table'
    });
    expect(commit.success).toBe(true);
  });
});

Shadow Database Workflow:

// tests/e2e/shadow-database.test.ts
describe('Shadow Database Workflow', () => {
  test('complete shadow testing cycle', async () => {
    const project = await setupTestProject();
    
    // Setup shadow database
    const setup = await setupShadowDatabase({
      projectPath: project.path,
      seedData: true
    });
    expect(setup.success).toBe(true);
    
    // Test migration
    const test = await testAgainstShadow({
      projectPath: project.path
    });
    expect(test.data.test.execution.successful).toBe(true);
    
    // Compare with main
    const comparison = await compareWithShadow({
      projectPath: project.path
    });
    expect(comparison.data.comparison.identical).toBe(false);
    
    // Cleanup
    const cleanup = await cleanupDevelopmentDatabases({
      projectPath: project.path
    });
    expect(cleanup.success).toBe(true);
  });
});
  • Test complete migration development workflows
  • Test error recovery and rollback scenarios
  • Test multi-user development scenarios
  • Test edge cases and boundary conditions
  • Test integration with different PostgreSQL versions

5. Performance Test Suite

Performance and load testing for scalability:

Performance Benchmarks:

// tests/performance/benchmarks.test.ts
describe('Performance Benchmarks', () => {
  test('schema analysis performance', async () => {
    const largeDb = await createLargeTestDatabase(1000); // 1000 tables
    
    const startTime = Date.now();
    const analysis = await analyzeSchema({ projectPath: largeDb.path });
    const duration = Date.now() - startTime;
    
    expect(analysis.success).toBe(true);
    expect(duration).toBeLessThan(5000); // Should complete within 5 seconds
    expect(analysis.data.tables).toHaveLength(1000);
  });

  test('idempotency testing performance', async () => {
    const project = await createTestProject();
    await project.addMigration('large-migration.sql', createLargeMigration());
    
    const startTime = Date.now();
    const test = await testMigrationIdempotency({
      projectPath: project.path,
      iterations: 5
    });
    const duration = Date.now() - startTime;
    
    expect(test.success).toBe(true);
    expect(duration).toBeLessThan(30000); // Should complete within 30 seconds
  });
});

Load Testing:

// tests/performance/load.test.ts
describe('Load Testing', () => {
  test('concurrent MCP tool usage', async () => {
    const projects = await Promise.all(
      Array(10).fill(0).map(() => createTestProject())
    );
    
    const startTime = Date.now();
    const results = await Promise.all(
      projects.map(project => getMigrationStatus({ projectPath: project.path }))
    );
    const duration = Date.now() - startTime;
    
    expect(results.every(r => r.success)).toBe(true);
    expect(duration).toBeLessThan(10000); // Should handle 10 concurrent requests within 10 seconds
  });
});
  • Test performance with large databases
  • Test concurrent tool usage
  • Test memory usage over time
  • Test resource cleanup efficiency
  • Test scalability limits

6. Test Infrastructure Utilities

Create comprehensive test utilities and helpers:

Test Database Manager:

// tests/utils/test-database.ts
export class TestDatabaseManager {
  async createDatabase(name: string): Promise<TestDatabase>;
  async createProject(options: ProjectOptions): Promise<TestProject>;
  async seedDatabase(db: TestDatabase, data: SeedData): Promise<void>;
  async cleanup(): Promise<void>;
}

export interface TestProject {
  path: string;
  name: string;
  database: TestDatabase;
  addMigration(filename: string, content: string): Promise<void>;
  getStatus(): Promise<ProjectStatus>;
  cleanup(): Promise<void>;
}

Mock Data Generators:

// tests/utils/mock-data.ts
export function generateMockMigration(type: 'table' | 'function' | 'index'): string;
export function generateLargeDatabase(tableCount: number): DatabaseSchema;
export function generateTestProject(options: ProjectOptions): ProjectConfiguration;
  • Create database setup/teardown utilities
  • Implement project scaffolding helpers
  • Add mock data generation functions
  • Create test assertion helpers
  • Implement performance measurement utilities

Coverage Requirements

Maintain ≥80% code coverage across all metrics:

  • Lines: 80% minimum coverage
  • Functions: 80% minimum coverage
  • Branches: 80% minimum coverage
  • Statements: 80% minimum coverage

Coverage verification script:

// scripts/check-coverage.js
const coverage = require('./coverage/coverage-summary.json');
const required = 80;

Object.entries(coverage.total).forEach(([metric, data]) => {
  if (data.pct < required) {
    console.error(`${metric} coverage ${data.pct}% below required ${required}%`);
    process.exit(1);
  }
});
console.log('✅ All coverage requirements met');

Claude Agent Guidance

Running Tests

# Run all tests
npm test

# Run specific test suites
npm run test:unit
npm run test:integration
npm run test:e2e

# Run with coverage
npm run test:coverage

# Check coverage requirements
npm run coverage:check

# Generate coverage report
npm run coverage:report

Test Development Workflow

// 1. Write failing test first (TDD)
test('should create migration with template', async () => {
  const result = await createMigration({
    projectPath: '/test/project',
    migrationName: 'add_users',
    template: 'table'
  });
  expect(result.success).toBe(true);
  expect(result.data.file).toContain('CREATE TABLE IF NOT EXISTS');
});

// 2. Implement feature to make test pass
// 3. Refactor while keeping tests green

Expected Test Behavior

  • All tests should pass consistently
  • Test failures should provide clear error messages
  • Performance tests should complete within time limits
  • Coverage should meet minimum requirements

Common Test Issues

  • Database connection failures: Ensure test databases are properly configured
  • File permission issues: Use proper test directories with write permissions
  • Timeout errors: Increase timeout for integration tests with real databases
  • Flaky tests: Use proper setup/teardown and avoid race conditions

Definition of Done

  • Complete test framework configured and working
  • All test suites implemented with comprehensive coverage
  • Performance tests validate scalability requirements
  • Test coverage meets ≥80% requirement across all metrics
  • CI/CD integration tests pass consistently
  • Test documentation complete and clear
  • Error messages provide actionable guidance
  • Test data cleanup works reliably

Estimated Effort

3-4 days

Dependencies

  • All previous issues (this validates the entire system)

Technical Notes for Claude Agents

Key Files to Create

  • tests/unit/**/*.test.ts - Unit test files
  • tests/integration/**/*.test.ts - Integration test files
  • tests/e2e/**/*.test.ts - End-to-end test files
  • tests/performance/**/*.test.ts - Performance test files
  • tests/utils/ - Test utilities and helpers
  • tests/fixtures/ - Test data and configurations
  • scripts/check-coverage.js - Coverage validation script

Test Database Strategy

  • Use Docker containers for consistent test environments
  • Create isolated test databases for each test
  • Implement proper cleanup to avoid test interference
  • Use database transactions for fast test isolation
  • Support multiple PostgreSQL versions

Performance Testing Guidelines

  • Set realistic performance targets based on typical usage
  • Test with various database sizes and complexities
  • Monitor memory usage and resource consumption
  • Use consistent test environments for reliable metrics
  • Implement automated performance regression detection