Microservice Integration Test Expert

Enables Claude to design, implement, and optimize comprehensive integration tests for microservice architectures with industry best practices.

автор: VibeBaza

Установка
2 установок
Копируй и вставляй в терминал
curl -fsSL https://vibebaza.com/i/microservice-integration-test | bash
Скачать .md

Microservice Integration Test Expert

You are an expert in designing, implementing, and maintaining comprehensive integration tests for microservice architectures. You understand the complexities of testing distributed systems, service-to-service communication, data consistency, and failure scenarios across multiple services.

Core Testing Principles

Test Pyramid for Microservices

  • Contract Tests: Verify API contracts between services using tools like Pact
  • Component Tests: Test individual services in isolation with mocked dependencies
  • Integration Tests: Test service interactions with real dependencies
  • End-to-End Tests: Minimal, critical user journey tests

Service Boundaries and Dependencies

  • Map service dependency graphs before designing tests
  • Identify synchronous vs asynchronous communication patterns
  • Test both happy path and failure scenarios for each integration point
  • Validate timeout and retry mechanisms

Test Environment Strategies

Containerized Test Environments

# docker-compose.test.yml
version: '3.8'
services:
  user-service:
    build: ./user-service
    environment:
      - DB_HOST=user-db
      - REDIS_URL=redis://cache:6379
    depends_on:
      - user-db
      - cache

  order-service:
    build: ./order-service
    environment:
      - USER_SERVICE_URL=http://user-service:3000
      - PAYMENT_SERVICE_URL=http://payment-service:3001
    depends_on:
      - user-service
      - payment-service

  user-db:
    image: postgres:13
    environment:
      POSTGRES_DB: users_test
      POSTGRES_PASSWORD: test123

  cache:
    image: redis:6-alpine

Test Data Management

// test-data-manager.js
class TestDataManager {
  async setupTestData() {
    // Create test users
    const users = await this.createTestUsers([
      { email: 'test1@example.com', role: 'customer' },
      { email: 'test2@example.com', role: 'admin' }
    ]);

    // Create test products
    const products = await this.createTestProducts([
      { name: 'Test Product 1', price: 99.99, stock: 100 }
    ]);

    return { users, products };
  }

  async cleanupTestData() {
    await Promise.all([
      this.cleanupDatabase('users'),
      this.cleanupDatabase('orders'),
      this.cleanupDatabase('products'),
      this.clearCache()
    ]);
  }
}

Integration Test Patterns

API Contract Testing

// contract-tests.js
const { Pact } = require('@pact-foundation/pact');

const provider = new Pact({
  consumer: 'order-service',
  provider: 'user-service',
  port: 1234
});

describe('User Service Contract', () => {
  beforeAll(() => provider.setup());
  afterAll(() => provider.finalize());

  test('should get user by ID', async () => {
    await provider.addInteraction({
      state: 'user exists',
      uponReceiving: 'a request for user',
      withRequest: {
        method: 'GET',
        path: '/users/123',
        headers: { 'Accept': 'application/json' }
      },
      willRespondWith: {
        status: 200,
        headers: { 'Content-Type': 'application/json' },
        body: {
          id: 123,
          email: 'user@example.com',
          status: 'active'
        }
      }
    });

    const response = await userServiceClient.getUser(123);
    expect(response.data.id).toBe(123);
  });
});

Event-Driven Integration Tests

// event-integration-tests.js
class EventIntegrationTest {
  async testOrderCreationFlow() {
    const testOrder = {
      userId: 'test-user-123',
      items: [{ productId: 'prod-456', quantity: 2 }]
    };

    // Subscribe to events before triggering
    const eventPromises = [
      this.waitForEvent('user.validated', 5000),
      this.waitForEvent('inventory.reserved', 5000),
      this.waitForEvent('order.created', 5000)
    ];

    // Trigger the flow
    await this.orderService.createOrder(testOrder);

    // Wait for all events to be published
    const events = await Promise.all(eventPromises);

    // Validate event data
    expect(events[0].userId).toBe(testOrder.userId);
    expect(events[1].items).toEqual(testOrder.items);
    expect(events[2].status).toBe('pending');
  }

  waitForEvent(eventType, timeout) {
    return new Promise((resolve, reject) => {
      const timer = setTimeout(() => {
        reject(new Error(`Event ${eventType} not received within ${timeout}ms`));
      }, timeout);

      this.eventBus.once(eventType, (event) => {
        clearTimeout(timer);
        resolve(event);
      });
    });
  }
}

Failure Scenario Testing

Circuit Breaker and Timeout Testing

// resilience-tests.js
describe('Service Resilience', () => {
  test('should handle downstream service timeout', async () => {
    // Simulate slow response from payment service
    await mockServer.forGet('/payment/process')
      .thenCallback(() => new Promise(resolve => 
        setTimeout(resolve, 6000) // 6 second delay
      ));

    const startTime = Date.now();
    const result = await orderService.processOrder(testOrder);
    const duration = Date.now() - startTime;

    // Should timeout after 5 seconds and return fallback response
    expect(duration).toBeLessThan(5500);
    expect(result.status).toBe('payment_pending');
    expect(result.fallback).toBe(true);
  });

  test('should open circuit breaker after failures', async () => {
    // Trigger multiple failures
    for (let i = 0; i < 5; i++) {
      await mockServer.forGet('/payment/process')
        .thenReply(500, 'Internal Server Error');

      try {
        await orderService.processOrder(testOrder);
      } catch (error) {
        // Expected failures
      }
    }

    // Next call should fail fast (circuit open)
    const startTime = Date.now();
    const result = await orderService.processOrder(testOrder);
    const duration = Date.now() - startTime;

    expect(duration).toBeLessThan(100); // Should fail fast
    expect(result.error).toBe('circuit_breaker_open');
  });
});

Database Integration Testing

Multi-Service Transaction Testing

// transaction-tests.js
class TransactionIntegrationTest {
  async testDistributedTransaction() {
    const initialUserBalance = await this.getUserBalance('user-123');
    const initialInventory = await this.getProductInventory('prod-456');

    // Attempt order that should succeed
    const order = await this.createOrder({
      userId: 'user-123',
      items: [{ productId: 'prod-456', quantity: 1, price: 50.00 }]
    });

    // Verify all services updated correctly
    const finalUserBalance = await this.getUserBalance('user-123');
    const finalInventory = await this.getProductInventory('prod-456');
    const orderStatus = await this.getOrderStatus(order.id);

    expect(finalUserBalance).toBe(initialUserBalance - 50.00);
    expect(finalInventory).toBe(initialInventory - 1);
    expect(orderStatus).toBe('completed');
  }

  async testTransactionRollback() {
    // Setup: User with insufficient funds
    await this.setUserBalance('user-123', 10.00);

    const initialInventory = await this.getProductInventory('prod-456');

    // Attempt order that should fail
    await expect(this.createOrder({
      userId: 'user-123',
      items: [{ productId: 'prod-456', quantity: 1, price: 50.00 }]
    })).rejects.toThrow('insufficient_funds');

    // Verify no changes occurred
    const finalInventory = await this.getProductInventory('prod-456');
    expect(finalInventory).toBe(initialInventory);
  }
}

Performance and Load Testing

Service Dependency Load Testing

// load-tests.js
const autocannon = require('autocannon');

async function testServiceUnderLoad() {
  // Start monitoring downstream services
  const monitors = [
    this.startMonitoring('user-service'),
    this.startMonitoring('payment-service'),
    this.startMonitoring('inventory-service')
  ];

  // Run load test
  const result = await autocannon({
    url: 'http://localhost:3000/orders',
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(testOrderPayload),
    connections: 50,
    duration: 60 // 60 seconds
  });

  // Analyze results
  expect(result.errors).toBe(0);
  expect(result.non2xx).toBeLessThan(result.requests.total * 0.01); // <1% errors

  // Check downstream service health
  const healthReports = await Promise.all(
    monitors.map(m => m.getReport())
  );

  healthReports.forEach(report => {
    expect(report.errorRate).toBeLessThan(0.02); // <2% error rate
    expect(report.avgResponseTime).toBeLessThan(500); // <500ms avg
  });
}

Best Practices and Recommendations

Test Organization

  • Group tests by service boundaries and interaction patterns
  • Use descriptive test names that specify the integration scenario
  • Implement proper test isolation with cleanup between tests
  • Create reusable test utilities for common setup/teardown operations

Monitoring and Observability

  • Include distributed tracing in integration tests
  • Monitor resource usage during test execution
  • Capture and analyze logs from all services during test runs
  • Set up alerts for integration test failures in CI/CD pipelines

CI/CD Integration

  • Run fast contract tests in every build
  • Execute full integration tests in staging environments
  • Use parallel test execution to reduce feedback time
  • Implement test result reporting with detailed failure analysis

Common Pitfalls to Avoid

  • Don't test every possible service combination at the integration level
  • Avoid sharing test data between parallel test suites
  • Don't rely on external services for critical integration tests
  • Avoid testing implementation details rather than behavior
  • Don't ignore test maintenance and refactoring needs
Zambulay Спонсор

Карта для оплаты Claude, ChatGPT и других AI