Skip to content

Jest

简介

Jest 是 Facebook 开发的一个功能全面的 JavaScript 测试框架,专注于简单性。它内置了断言、测试覆盖率、Mock 功能、快照测试等特性,几乎不需要配置就可以开始使用,是目前最流行的 JavaScript 测试解决方案之一。

核心特性

零配置测试平台

Jest 提供了开箱即用的体验,无需复杂配置:

bash
# 安装 Jest
npm install --save-dev jest

# 添加测试脚本到 package.json
{
  "scripts": {
    "test": "jest"
  }
}

# 运行测试
npm test

快照测试

快照测试可以捕获组件或数据结构的渲染结果,并将其与之前保存的快照进行比较:

javascript
it('renders correctly', () => {
  const tree = renderer
    .create(<Link page="https://example.com">Example</Link>)
    .toJSON();
  expect(tree).toMatchSnapshot();
});

Mock 功能

Jest 提供了强大的 Mock 功能,可以模拟函数、模块和定时器:

javascript
// 模拟函数
const mockFn = jest.fn();
mockFn.mockReturnValue(42);
console.log(mockFn()); // 42

// 模拟模块
jest.mock('./math');

// 模拟定时器
jest.useFakeTimers();
setTimeout(() => {}, 1000);
jest.runAllTimers();

基本用法

编写测试

javascript
// sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;

// sum.test.js
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

测试组织

javascript
describe('计算器功能测试', () => {
  beforeEach(() => {
    // 每个测试前的设置
  });

  afterEach(() => {
    // 每个测试后的清理
  });

  test('加法运算', () => {
    expect(sum(1, 2)).toBe(3);
  });

  test('减法运算', () => {
    expect(subtract(5, 2)).toBe(3);
  });
});

常用匹配器

javascript
// 精确匹配
expect(value).toBe(2);  // 使用 Object.is 比较
expect(value).toEqual({ a: 1 });  // 递归比较对象的值

// 真值检查
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();

// 数字比较
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThanOrEqual(5);

// 字符串
expect('team').toMatch(/tea/);

// 数组
expect(['apple', 'banana']).toContain('apple');

// 异常
expect(() => { throw new Error('错误') }).toThrow();

高级功能

异步测试

javascript
// Promise
test('异步数据获取', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});

// Async/Await
test('异步数据获取', async () => {
  const data = await fetchData();
  expect(data).toBe('peanut butter');
});

// 回调
test('异步回调', done => {
  function callback(data) {
    try {
      expect(data).toBe('peanut butter');
      done();
    } catch (error) {
      done(error);
    }
  }
  fetchData(callback);
});

测试覆盖率

bash
# 运行测试并收集覆盖率
npm test -- --coverage
javascript
// jest.config.js
module.exports = {
  collectCoverage: true,
  collectCoverageFrom: [
    '**/*.{js,jsx}',
    '!**/node_modules/**',
    '!**/vendor/**'
  ],
  coverageThreshold: {
    global: {
      branches: 80,
      functions: 80,
      lines: 80,
      statements: 80
    }
  }
};

测试 React 组件

javascript
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';

test('按钮点击事件', () => {
  const handleClick = jest.fn();
  render(<Button onClick={handleClick}>点击我</Button>);
  
  fireEvent.click(screen.getByText('点击我'));
  expect(handleClick).toHaveBeenCalledTimes(1);
});

配置选项

jest.config.js

javascript
module.exports = {
  // 测试环境
  testEnvironment: 'jsdom',
  
  // 测试文件匹配模式
  testMatch: ['**/__tests__/**/*.js', '**/?(*.)+(spec|test).js'],
  
  // 转换器
  transform: {
    '^.+\.jsx?$': 'babel-jest',
    '^.+\.tsx?$': 'ts-jest'
  },
  
  // 模块名映射
  moduleNameMapper: {
    '\.(css|less)$': '<rootDir>/__mocks__/styleMock.js',
    '\.(jpg|jpeg|png|gif)$': '<rootDir>/__mocks__/fileMock.js',
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  
  // 设置测试超时时间(毫秒)
  testTimeout: 10000
};

最佳实践

测试组织

  • 使用 describe 对相关测试进行分组
  • 使用 beforeEachafterEach 设置和清理测试环境
  • 保持测试独立,避免测试间的依赖

命名约定

  • 测试文件使用 .test.js.spec.js 后缀
  • 测试目录使用 __tests__ 命名
  • 测试描述应清晰表达预期行为

Mock 策略

  • 尽量模拟外部依赖,如 API 调用、数据库访问
  • 使用 jest.spyOn 监视对象方法的调用
  • 使用 jest.mock 替换整个模块的实现

常见问题与解决方案

测试超时

javascript
// 增加单个测试的超时时间
test('长时间运行的测试', () => {
  // ...
}, 30000); // 30秒

// 或在配置中全局设置
// jest.config.js
module.exports = {
  testTimeout: 30000
};

模块路径解析

javascript
// jest.config.js
module.exports = {
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1'
  }
};

测试环境问题

javascript
// 设置不同的测试环境
// jest.config.js
module.exports = {
  testEnvironment: 'node', // 或 'jsdom'
};

与其他测试工具对比

特性JestMochaVitest
开箱即用优秀需配置优秀
执行速度良好良好极快
内置断言
内置覆盖率
快照测试支持不支持支持
并行测试支持支持支持
社区生态丰富丰富成长中

学习资源