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