Jest 性能优化 #
性能优化概述 #
测试速度对开发效率至关重要。Jest 提供了多种优化手段来提升测试执行速度。
text
┌─────────────────────────────────────────────────────────────┐
│ 性能优化策略 │
├─────────────────────────────────────────────────────────────┤
│ 1. 并行执行 - 充分利用多核 CPU │
│ 2. 缓存优化 - 避免重复工作 │
│ 3. 增量测试 - 只运行相关测试 │
│ 4. 测试隔离 - 减少测试间依赖 │
│ 5. 配置优化 - 减少不必要的处理 │
└─────────────────────────────────────────────────────────────┘
并行执行 #
maxWorkers 配置 #
javascript
// jest.config.js
module.exports = {
maxWorkers: '50%', // 使用 50% CPU 核心
// 或
maxWorkers: 4, // 固定使用 4 个 worker
// 或
maxWorkers: 1, // 串行执行
};
命令行指定 #
bash
# 使用 50% CPU
jest --maxWorkers=50%
# 使用固定数量
jest --maxWorkers=4
# 串行执行
jest --runInBand
CI 环境配置 #
javascript
// jest.config.js
module.exports = {
maxWorkers: process.env.CI ? 2 : '50%',
};
不同场景的建议 #
| 场景 | 建议 maxWorkers |
|---|---|
| 本地开发 | 50% |
| CI 环境 | 2-4 |
| 大型项目 | 4-8 |
| 内存受限 | 1-2 |
缓存优化 #
启用缓存 #
javascript
// jest.config.js
module.exports = {
cache: true,
cacheDirectory: '/tmp/jest_cache',
};
清除缓存 #
bash
# 清除缓存
jest --clearCache
# 忽略缓存运行
jest --no-cache
缓存位置 #
bash
# 查看缓存位置
jest --showConfig | grep cacheDirectory
增量测试 #
只运行修改的测试 #
bash
# 只运行与修改文件相关的测试
jest --onlyChanged
# 只运行与 git 变更相关的测试
jest --changedSince=main
Watch 模式 #
bash
# 监听模式
jest --watch
# 监听所有文件
jest --watchAll
配置 watch 插件 #
javascript
// jest.config.js
module.exports = {
watchPlugins: [
'jest-watch-typeahead/filename',
'jest-watch-typeahead/testname',
],
};
测试隔离优化 #
避免共享状态 #
javascript
// ❌ 不好的做法
describe('shared state', () => {
let counter = 0;
test('test 1', () => {
counter++;
expect(counter).toBe(1);
});
test('test 2', () => {
// 依赖 test 1 的状态
expect(counter).toBe(1);
});
});
// ✅ 好的做法
describe('isolated state', () => {
let counter;
beforeEach(() => {
counter = 0;
});
test('test 1', () => {
counter++;
expect(counter).toBe(1);
});
test('test 2', () => {
expect(counter).toBe(0);
});
});
减少钩子开销 #
javascript
// ❌ 不好的做法 - 每个测试都执行重操作
beforeEach(async () => {
await setupDatabase();
await seedData();
});
// ✅ 好的做法 - 只在需要时执行
describe('database tests', () => {
beforeAll(async () => {
await setupDatabase();
});
beforeEach(async () => {
await clearData();
});
});
转换优化 #
优化 transformIgnorePatterns #
javascript
// jest.config.js
module.exports = {
transformIgnorePatterns: [
// 只转换需要的 node_modules
'node_modules/(?!(react-router-dom|axios)/)',
],
};
使用更快的转换器 #
javascript
// 使用 esbuild-jest 替代 babel-jest
module.exports = {
transform: {
'^.+\\.(js|jsx|ts|tsx)$': 'esbuild-jest',
},
};
跳过不必要的转换 #
javascript
module.exports = {
transform: {
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
},
transformIgnorePatterns: [
'node_modules/',
'\\.css$',
'\\.scss$',
],
};
Mock 优化 #
减少不必要的 Mock #
javascript
// ❌ 不好的做法 - Mock 所有依赖
jest.mock('lodash');
jest.mock('axios');
jest.mock('moment');
// ✅ 好的做法 - 只 Mock 必要的依赖
jest.mock('axios');
使用轻量 Mock #
javascript
// ❌ 不好的做法 - 复杂的 Mock
jest.mock('./api', () => {
const original = jest.requireActual('./api');
return {
...original,
fetch: jest.fn(() => {
return new Promise((resolve) => {
setTimeout(() => resolve({ data: 'test' }), 100);
});
}),
};
});
// ✅ 好的做法 - 简单的 Mock
jest.mock('./api', () => ({
fetch: jest.fn().mockResolvedValue({ data: 'test' }),
}));
测试文件优化 #
拆分大测试文件 #
javascript
// ❌ 不好的做法 - 一个大文件
// user.test.js - 1000+ 行
// ✅ 好的做法 - 拆分为多个文件
// user.auth.test.js
// user.profile.test.js
// user.settings.test.js
使用 test.concurrent #
javascript
// 并行运行测试
test.concurrent('concurrent test 1', async () => {
await someAsyncOperation();
});
test.concurrent('concurrent test 2', async () => {
await someAsyncOperation();
});
跳过慢测试 #
javascript
// 使用 test.skip 跳过慢测试
test.skip('slow test', () => {
// 耗时测试
});
// 条件跳过
const runSlowTests = process.env.RUN_SLOW_TESTS === 'true';
const testFn = runSlowTests ? test : test.skip;
testFn('slow test', () => {
// 耗时测试
});
快照优化 #
减小快照大小 #
javascript
// ❌ 不好的做法 - 整个组件树
expect(container.innerHTML).toMatchSnapshot();
// ✅ 好的做法 - 关键部分
expect(screen.getByRole('button')).toMatchSnapshot();
使用内联快照 #
javascript
// 内联快照更快
expect(value).toMatchInlineSnapshot(`"expected value"`);
配置优化 #
减少测试匹配范围 #
javascript
// jest.config.js
module.exports = {
testMatch: [
'<rootDir>/src/**/*.test.{js,ts}',
],
testPathIgnorePatterns: [
'/node_modules/',
'/dist/',
'/coverage/',
],
};
减少覆盖率收集 #
javascript
// 只在需要时收集覆盖率
module.exports = {
collectCoverage: false, // 默认不收集
};
// CI 中启用
// jest --coverage
优化模块解析 #
javascript
module.exports = {
moduleDirectories: ['node_modules', 'src'],
modulePaths: ['<rootDir>/src'],
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};
性能分析 #
使用 --detectLeaks #
bash
# 检测内存泄漏
jest --detectLeaks
使用 --logHeapUsage #
bash
# 记录内存使用
jest --logHeapUsage
使用 --detectOpenHandles #
bash
# 检测未关闭的句柄
jest --detectOpenHandles
性能分析脚本 #
javascript
// package.json
{
"scripts": {
"test:perf": "node scripts/test-performance.js"
}
}
// scripts/test-performance.js
const { execSync } = require('child_process');
const start = Date.now();
execSync('jest --runInBand', { stdio: 'inherit' });
const duration = Date.now() - start;
console.log(`Tests completed in ${duration}ms`);
CI 优化 #
分片测试 #
bash
# 将测试分为 4 片,运行第 1 片
jest --shard=1/4
# 在 CI 中并行运行
# Job 1: jest --shard=1/4
# Job 2: jest --shard=2/4
# Job 3: jest --shard=3/4
# Job 4: jest --shard=4/4
GitHub Actions 分片 #
yaml
jobs:
test:
strategy:
matrix:
shard: [1/4, 2/4, 3/4, 4/4]
steps:
- run: npm test -- --shard=${{ matrix.shard }}
缓存依赖 #
yaml
# GitHub Actions
- name: Cache node modules
uses: actions/cache@v3
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
- name: Cache Jest
uses: actions/cache@v3
with:
path: .jest-cache
key: ${{ runner.os }}-jest-${{ hashFiles('**/package-lock.json') }}
性能优化清单 #
text
□ 并行执行
├── 配置合理的 maxWorkers
├── CI 环境使用固定 worker 数
└── 使用 test.concurrent
□ 缓存优化
├── 启用 Jest 缓存
├── CI 中缓存依赖
└── 定期清理缓存
□ 增量测试
├── 使用 --onlyChanged
├── 使用 --changedSince
└── Watch 模式开发
□ 测试隔离
├── 避免共享状态
├── 减少钩子开销
└── 清理 Mock
□ 转换优化
├── 优化 transformIgnorePatterns
├── 使用更快的转换器
└── 跳过不必要的转换
□ Mock 优化
├── 减少不必要的 Mock
├── 使用轻量 Mock
└── 清理 Mock
□ 配置优化
├── 减少测试匹配范围
├── 减少覆盖率收集
└── 优化模块解析
□ CI 优化
├── 使用测试分片
├── 缓存依赖
└── 并行运行
性能基准 #
测试执行时间 #
| 项目规模 | 建议执行时间 |
|---|---|
| 小型项目 | < 10s |
| 中型项目 | < 30s |
| 大型项目 | < 60s |
优化前后对比 #
text
优化前:
- 测试数量: 500
- 执行时间: 120s
- 内存使用: 2GB
优化后:
- 测试数量: 500
- 执行时间: 30s (↓75%)
- 内存使用: 800MB (↓60%)
下一步 #
现在你已经掌握了 Jest 性能优化,接下来学习 调试技巧 解决测试问题!
最后更新:2026-03-28