Jest 性能优化 #

性能问题分析 #

常见性能瓶颈 #

text
┌─────────────────────────────────────────────────────────────┐
│                    性能瓶颈类型                              │
├─────────────────────────────────────────────────────────────┤
│  1. 测试数量太多 - 需要优化测试策略                          │
│  2. 串行执行慢 - 需要并行化                                  │
│  3. 重复初始化 - 需要优化生命周期                            │
│  4. 外部依赖慢 - 需要 Mock                                   │
│  5. 配置不当 - 需要优化配置                                  │
└─────────────────────────────────────────────────────────────┘

性能分析工具 #

bash
# 显示测试时间
jest --verbose

# 检测慢测试
jest --detectOpenHandles --forceExit

# 分析测试性能
jest --logHeapUsage

并行执行优化 #

maxWorkers 配置 #

javascript
// jest.config.js
module.exports = {
  // 使用 50% 的 CPU 核心
  maxWorkers: '50%',
  
  // 或指定具体数量
  maxWorkers: 4,
  
  // CI 环境使用更少的工作进程
  maxWorkers: process.env.CI ? 2 : '50%',
};
bash
# 命令行指定
jest --maxWorkers=4
jest --maxWorkers=50%

并发控制 #

javascript
module.exports = {
  // 控制同时执行的测试数量
  maxConcurrency: 5,
};

测试文件分片 #

bash
# 分片运行测试
jest --shard=1/3  # 运行第一部分
jest --shard=2/3  # 运行第二部分
jest --shard=3/3  # 运行第三部分

# CI 中并行运行
# GitHub Actions matrix
yaml
# .github/workflows/test.yml
jobs:
  test:
    strategy:
      matrix:
        shard: [1/4, 2/4, 3/4, 4/4]
    steps:
      - run: npm test -- --shard=${{ matrix.shard }}

缓存优化 #

启用缓存 #

javascript
// jest.config.js
module.exports = {
  cache: true,
  cacheDirectory: '/tmp/jest_cache',
};

清除缓存 #

bash
# 清除缓存
jest --clearCache

# 忽略缓存运行
jest --no-cache

缓存策略 #

javascript
// jest.config.js
module.exports = {
  // 缓存依赖
  cache: true,
  
  // 监视模式缓存
  watchPathIgnorePatterns: [
    '/node_modules/',
    '/dist/',
    '/coverage/',
  ],
};

增量测试 #

只运行修改的测试 #

bash
# 只运行修改的文件
jest --onlyChanged

# 只运行相关测试
jest --findRelatedTests src/utils/math.js

# 基于Git变更
jest --changedSince=main

配置增量测试 #

javascript
// jest.config.js
module.exports = {
  // 检测未提交的变更
  onlyChanged: true,
  
  // Git 相关配置
  changedFilesWithAncestor: true,
};

测试隔离优化 #

串行执行 #

bash
# 串行执行(调试时使用)
jest --runInBand

# 简写
jest -i

减少重复初始化 #

javascript
// ❌ 不好的做法 - 每个测试都创建
describe('Bad', () => {
  test('test 1', () => {
    const db = new Database(); // 重复创建
  });
  test('test 2', () => {
    const db = new Database(); // 重复创建
  });
});

// ✅ 好的做法 - 共享初始化
describe('Good', () => {
  let db;

  beforeAll(() => {
    db = new Database(); // 只创建一次
  });

  afterAll(() => {
    db.close();
  });

  test('test 1', () => {
    // 使用 db
  });
  test('test 2', () => {
    // 使用 db
  });
});

Mock 优化 #

Mock 外部依赖 #

javascript
// ❌ 不好的做法 - 真实网络请求
test('fetches user', async () => {
  const user = await fetchUser(1); // 真实请求
  expect(user).toBeDefined();
});

// ✅ 好的做法 - Mock 网络请求
jest.mock('./api');
test('fetches user', async () => {
  fetchUser.mockResolvedValue({ id: 1, name: 'John' });
  const user = await fetchUser(1);
  expect(user).toBeDefined();
});

Mock 重型操作 #

javascript
// Mock 文件系统
jest.mock('fs', () => ({
  readFileSync: jest.fn(() => 'mocked content'),
}));

// Mock 数据库
jest.mock('./database', () => ({
  query: jest.fn(() => Promise.resolve([{ id: 1 }])),
}));

测试文件优化 #

拆分大文件 #

javascript
// ❌ 不好的做法 - 一个大文件
// user.test.js - 1000 行

// ✅ 好的做法 - 按功能拆分
// user.auth.test.js
// user.profile.test.js
// user.settings.test.js

减少不必要的测试 #

javascript
// ❌ 不好的做法 - 测试库的功能
test('array has length', () => {
  const arr = [1, 2, 3];
  expect(arr.length).toBe(3); // 不需要测试
});

// ✅ 好的做法 - 测试业务逻辑
test('filters active users', () => {
  const users = [
    { id: 1, active: true },
    { id: 2, active: false },
  ];
  const active = filterActiveUsers(users);
  expect(active).toHaveLength(1);
});

配置优化 #

转换优化 #

javascript
// jest.config.js
module.exports = {
  // 只转换需要的文件
  transformIgnorePatterns: [
    '/node_modules/(?!(@myorg|lodash-es)/)',
  ],
  
  // 跳过不需要转换的文件
  transform: {
    '^.+\\.js$': ['babel-jest', { compact: true }],
  },
};

测试匹配优化 #

javascript
module.exports = {
  // 精确匹配测试文件
  testMatch: [
    '<rootDir>/src/**/*.test.js',
  ],
  
  // 忽略不需要的目录
  testPathIgnorePatterns: [
    '/node_modules/',
    '/dist/',
    '/coverage/',
  ],
};

监视模式优化 #

javascript
module.exports = {
  // 监视插件
  watchPlugins: [
    'jest-watch-typeahead/filename',
    'jest-watch-typeahead/testname',
  ],
  
  // 忽略监视
  watchPathIgnorePatterns: [
    '/node_modules/',
    '/dist/',
    '/coverage/',
  ],
};

性能监控 #

测试时间报告 #

javascript
// customReporter.js
class PerformanceReporter {
  onTestResult(test, testResult) {
    const slowTests = testResult.testResults
      .filter(t => t.duration > 1000)
      .map(t => ({ name: t.fullName, duration: t.duration }));
    
    if (slowTests.length > 0) {
      console.log('\nSlow tests:');
      slowTests.forEach(t => {
        console.log(`  ${t.name}: ${t.duration}ms`);
      });
    }
  }
}

module.exports = PerformanceReporter;

内存监控 #

bash
# 监控内存使用
jest --logHeapUsage

# 限制内存
node --max-old-space-size=4096 $(which jest)

CI 优化 #

CI 配置 #

javascript
// jest.config.js
const isCI = process.env.CI === 'true';

module.exports = {
  // CI 环境优化
  cache: !isCI,
  maxWorkers: isCI ? 2 : '50%',
  coverage: isCI,
  ci: isCI,
};

GitHub Actions 优化 #

yaml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      
      # 缓存依赖
      - uses: actions/cache@v3
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
      
      # 缓存 Jest
      - uses: actions/cache@v3
        with:
          path: /tmp/jest_cache
          key: ${{ runner.os }}-jest-${{ hashFiles('**/*.js') }}
      
      - run: npm ci
      - run: npm test -- --maxWorkers=2 --ci

性能优化清单 #

检查清单 #

text
□ 使用并行执行
□ 启用缓存
□ Mock 外部依赖
□ 优化测试生命周期
□ 拆分大测试文件
□ 使用增量测试
□ 配置合理的 maxWorkers
□ 忽略不需要的文件
□ 监控慢测试
□ CI 环境优化配置

性能对比 #

优化前后对比 #

text
优化前:
- 测试时间: 120s
- 内存使用: 2GB
- CPU 使用: 25%

优化后:
- 测试时间: 30s (提升 75%)
- 内存使用: 1GB (减少 50%)
- CPU 使用: 80% (充分利用)

下一步 #

现在你已经掌握了 Jest 性能优化,接下来学习 调试技巧 解决测试问题!

最后更新:2026-03-28