testingperformance-testing

doanchienthangdev's avatarfrom doanchienthangdev

Performance testing patterns including load testing, stress testing, benchmarking, and profiling for optimal application performance

⭐0stars🔀0forks📁View on GitHub🕐Updated Jan 8, 2026

When & Why to Use This Skill

This Claude skill provides a comprehensive framework for performance testing, encompassing load testing, stress testing, benchmarking, and profiling. It is designed to help developers and QA engineers optimize application speed, scalability, and resource efficiency through standardized patterns and actionable code templates for modern tools like k6, Vitest, and Node.js.

Use Cases

  • Benchmarking critical algorithms and functions to ensure they meet execution time requirements (e.g., sorting, hashing, or JSON parsing).
  • Simulating high-concurrency user traffic using k6 to validate API scalability and response time SLAs (Service Level Agreements).
  • Conducting stress tests to identify system breaking points and verify recovery behavior under extreme memory or connection pressure.
  • Detecting and preventing memory leaks in Node.js applications through automated heap snapshots and memory usage tracking.
  • Integrating automated performance budgets and regression checks into CI/CD pipelines using GitHub Actions to maintain performance standards.
nametesting/performance-testing
descriptionPerformance testing patterns including load testing, stress testing, benchmarking, and profiling for optimal application performance
categorytesting

Performance Testing

Comprehensive performance testing for speed, scalability, and resource efficiency.

Quick Start

# Run benchmarks
npm run test:performance

# Profile with Node.js
node --prof app.js
node --prof-process isolate-*.log > profile.txt

# Load testing with k6
k6 run load-test.js

Types of Performance Tests

1. Benchmark Tests

Measure execution time of specific operations.

import { describe, it, expect } from 'vitest';

describe('Performance Benchmarks', () => {
  function timeExecution(fn, iterations = 1000) {
    const start = performance.now();
    for (let i = 0; i < iterations; i++) {
      fn();
    }
    const end = performance.now();
    return (end - start) / iterations;
  }

  it('sorts 1000 items under 1ms', () => {
    const data = Array(1000).fill().map(() => Math.random());
    const time = timeExecution(() => [...data].sort((a, b) => a - b), 100);
    expect(time).toBeLessThan(1);
  });

  it('hashes string under 0.1ms', () => {
    const time = timeExecution(() => hashString('test-string'), 10000);
    expect(time).toBeLessThan(0.1);
  });

  it('parses JSON under 0.5ms', () => {
    const json = JSON.stringify({ users: Array(100).fill({ name: 'test' }) });
    const time = timeExecution(() => JSON.parse(json), 1000);
    expect(time).toBeLessThan(0.5);
  });
});

2. Load Tests

Simulate concurrent users to test scalability.

// k6 load test script
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '1m', target: 50 },   // Ramp up to 50 users
    { duration: '3m', target: 50 },   // Stay at 50 users
    { duration: '1m', target: 100 },  // Ramp up to 100
    { duration: '3m', target: 100 },  // Stay at 100
    { duration: '1m', target: 0 },    // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<200'], // 95% under 200ms
    http_req_failed: ['rate<0.01'],   // Error rate < 1%
  },
};

export default function () {
  const res = http.get('https://api.example.com/users');

  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 200ms': (r) => r.timings.duration < 200,
  });

  sleep(1);
}

3. Stress Tests

Push system beyond normal limits.

describe('Stress Tests', () => {
  it('handles 10000 concurrent connections', async () => {
    const connections = Array(10000).fill().map(async () => {
      const ws = new WebSocket('ws://localhost:3000');
      return new Promise((resolve, reject) => {
        ws.onopen = () => resolve(ws);
        ws.onerror = reject;
        setTimeout(() => reject(new Error('timeout')), 5000);
      });
    });

    const results = await Promise.allSettled(connections);
    const successful = results.filter(r => r.status === 'fulfilled');
    expect(successful.length).toBeGreaterThan(9000);
  });

  it('recovers after memory pressure', async () => {
    const allocations = [];

    // Allocate memory
    for (let i = 0; i < 100; i++) {
      allocations.push(new Array(1000000).fill('x'));
    }

    // Force GC and clear
    allocations.length = 0;
    if (global.gc) global.gc();

    // System should still function
    const result = await api.get('/health');
    expect(result.status).toBe(200);
  });
});

4. Memory Tests

Detect memory leaks and inefficiencies.

describe('Memory Tests', () => {
  it('does not leak memory on repeated operations', async () => {
    const before = process.memoryUsage().heapUsed;

    for (let i = 0; i < 10000; i++) {
      await processRequest({ data: 'test' });
    }

    if (global.gc) global.gc();
    await new Promise(r => setTimeout(r, 100));

    const after = process.memoryUsage().heapUsed;
    const leaked = after - before;

    expect(leaked).toBeLessThan(10 * 1024 * 1024); // 10MB
  });

  it('releases event listeners', () => {
    const emitter = new EventEmitter();
    const before = emitter.listenerCount('event');

    for (let i = 0; i < 100; i++) {
      const handler = () => {};
      emitter.on('event', handler);
      emitter.off('event', handler);
    }

    const after = emitter.listenerCount('event');
    expect(after).toBe(before);
  });
});

API Response Time Tests

describe('API Performance', () => {
  const SLA = {
    p50: 50,   // 50th percentile under 50ms
    p95: 200,  // 95th percentile under 200ms
    p99: 500,  // 99th percentile under 500ms
  };

  it('meets response time SLA', async () => {
    const times = [];

    for (let i = 0; i < 1000; i++) {
      const start = performance.now();
      await api.get('/users');
      times.push(performance.now() - start);
    }

    times.sort((a, b) => a - b);

    const p50 = times[Math.floor(times.length * 0.50)];
    const p95 = times[Math.floor(times.length * 0.95)];
    const p99 = times[Math.floor(times.length * 0.99)];

    expect(p50).toBeLessThan(SLA.p50);
    expect(p95).toBeLessThan(SLA.p95);
    expect(p99).toBeLessThan(SLA.p99);
  });
});

Database Performance Tests

describe('Database Performance', () => {
  it('query executes under 10ms', async () => {
    const start = performance.now();
    await db.query('SELECT * FROM users WHERE id = ?', [1]);
    const duration = performance.now() - start;
    expect(duration).toBeLessThan(10);
  });

  it('handles 100 concurrent queries', async () => {
    const queries = Array(100).fill().map(() =>
      db.query('SELECT * FROM users LIMIT 10')
    );

    const start = performance.now();
    await Promise.all(queries);
    const duration = performance.now() - start;

    expect(duration).toBeLessThan(1000);
  });

  it('insert batch is efficient', async () => {
    const records = Array(1000).fill().map((_, i) => ({
      name: `User ${i}`,
      email: `user${i}@test.com`,
    }));

    const start = performance.now();
    await db.batchInsert('users', records);
    const duration = performance.now() - start;

    expect(duration).toBeLessThan(500);
  });
});

Profiling Patterns

CPU Profiling

const v8Profiler = require('v8-profiler-next');

async function profileCPU(fn, name) {
  v8Profiler.startProfiling(name);

  await fn();

  const profile = v8Profiler.stopProfiling(name);
  profile.export((error, result) => {
    fs.writeFileSync(`${name}.cpuprofile`, result);
  });
}

Memory Profiling

function takeHeapSnapshot(name) {
  const snapshot = v8.writeHeapSnapshot();
  console.log(`Heap snapshot written to ${snapshot}`);
}

// In test
it('memory usage is stable', async () => {
  takeHeapSnapshot('before');

  for (let i = 0; i < 10000; i++) {
    await processData();
  }

  if (global.gc) global.gc();
  takeHeapSnapshot('after');
});

Performance Budgets

const budgets = {
  'First Contentful Paint': 1500,
  'Time to Interactive': 3500,
  'Total Bundle Size': 250 * 1024,
  'API Response Time': 200,
};

describe('Performance Budgets', () => {
  it('bundle size within budget', async () => {
    const stats = require('./dist/stats.json');
    const totalSize = stats.assets
      .filter(a => a.name.endsWith('.js'))
      .reduce((sum, a) => sum + a.size, 0);

    expect(totalSize).toBeLessThan(budgets['Total Bundle Size']);
  });
});

Continuous Performance Testing

GitHub Actions

name: Performance Tests

on:
  push:
    branches: [main]
  pull_request:

jobs:
  performance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - run: npm ci
      - run: npm run test:performance

      - name: Compare with baseline
        run: |
          npm run benchmark:compare -- --baseline main

When to Use

  • Before major releases
  • After performance-critical changes
  • During capacity planning
  • When SLA monitoring shows degradation
  • As part of CI/CD pipeline

Anti-Patterns

  1. Testing on Development Hardware: Use production-like environment
  2. Ignoring Warmup: JIT compilation affects first runs
  3. Single Metric Focus: Monitor multiple dimensions
  4. No Baseline: Always compare against baseline
  5. Flaky Thresholds: Use percentiles, not averages