Post

Jest测试框架使用

Jest测试框架使用

Jest 简介

Jest 是什么?主要用途是?

Jest 是一个由 Facebook 维护的 JavaScript 测试框架,主要用于测试 JavaScript 和 TypeScript 代码,特别是 React 应用。它是一个 零配置(out-of-the-box) 的测试框架,提供了强大的功能,如:

  • 单元测试(Unit Testing)——测试函数或模块的独立功能
  • 集成测试(Integration Testing)——测试多个模块之间的交互
  • 快照测试(Snapshot Testing)——检查 UI 组件的输出是否发生变化
  • Mock 功能(Mocking)——模拟函数、模块、定时器、API 请求等
  • 异步代码测试(Promise、async/await、回调)

Jest 包含了 测试运行器(Test Runner)、断言库(Assertion Library)、Mock 机制 和 覆盖率报告(Coverage Report),因此相比 Mocha、Jasmine 等框架,Jest 无需额外配置即可使用

Jest 的主要用途

  1. 测试 JavaScript/TypeScript 代码
  2. 测试前端框架(React, Vue, Angular)
  3. 测试 Node.js 应用(API、数据库交互等)
  4. 模拟 API 请求,测试服务端交互
  5. 确保 UI 组件的稳定性(快照测试)

示例:基本的 Jest 测试

1
2
3
4
5
// sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;
1
2
3
4
5
6
// sum.test.js
const sum = require('./sum');

test('1 + 2 should be 3', () => {
  expect(sum(1, 2)).toBe(3);
});

运行 Jest

1
npx jest

输出

1
2
PASS  ./sum.test.js
✓ 1 + 2 should be 3

如何使用 Jest 运行测试?

Jest 提供了多种方式来运行测试,常见的方法如下:

1. 直接运行 Jest

如果已经安装了 Jest,可以使用以下命令运行所有测试:

1
npx jest

或在 package.json 中添加 Jest 脚本:

1
2
3
4
5
{
  "scripts": {
    "test": "jest"
  }
}

然后执行:

1
npm test

或者:

1
yarn test

2. 运行特定的测试文件

1
npx jest sum.test.js

如果测试文件在 tests/ 目录下:

1
npx jest tests/myTest.test.js

3. 运行带有特定名称的测试

可以使用 -t 选项运行匹配某个测试名称的测试:

1
npx jest -t "should return 3 when adding 1 and 2"

这将在所有测试文件中查找包含 should return 3 when adding 1 and 2 的测试,并只运行这些测试。


4. 运行测试并显示覆盖率

如果想要查看测试覆盖率:

1
npx jest --coverage

这将生成一个覆盖率报告,显示每个文件的测试覆盖率(语句、分支、函数、行数)。


5. 运行 Jest 并启用调试模式

如果需要调试 Jest 测试,可以使用:

1
node --inspect-brk node_modules/.bin/jest --runInBand

或者:

1
npx jest --runInBand --detectOpenHandles

--runInBand 让 Jest 在单个进程中运行,有助于调试。


在哪些场景下使用 jest --watch

jest --watch 用于监听文件变动,并在文件更改时自动重新运行测试,适用于开发过程中需要频繁修改代码和测试的场景。

使用方式

1
npx jest --watch

或者:

1
npm test -- --watch

适用场景

  • TDD(测试驱动开发) —— 希望实时运行测试,并在修改代码后立即得到反馈。
  • 大规模项目 —— 在大型项目中,可以减少 Jest 启动的开销,只运行受影响的测试,提高效率。
  • 调试特定功能 —— 在开发某个模块时,可以专注于该模块的测试,避免重复运行所有测试文件。
  • CI/CD 之外的本地开发 —— 在 CI/CD 中通常不会使用 --watch,但本地开发时,它可以极大提高开发效率。

如果只想监听受影响的文件,可以使用:

1
npx jest --watchAll

1. 测试同步代码

同步代码测试相对简单,只需使用 Jest 的 expect() 进行断言。

示例:同步函数测试

1
2
3
4
5
// math.js
function add(a, b) {
  return a + b;
}
module.exports = add;
1
2
3
4
5
6
// math.test.js
const add = require('./math');

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

运行 Jest

1
npx jest

输出

1
2
PASS  ./math.test.js
✓ adds 2 + 3 to equal 5

2. 测试异步代码

Jest 提供了多种方式来测试异步代码,主要有回调函数、Promise 和 async/await

2.1 测试使用回调函数的异步代码

如果被测试的函数接受 回调函数 作为参数,需要在 Jest 的 test() 中使用 done 来确保 Jest 在回调执行完成后才结束测试。

示例:使用回调函数

1
2
3
4
5
6
7
// fetchData.js
function fetchData(callback) {
  setTimeout(() => {
    callback('data received');
  }, 1000);
}
module.exports = fetchData;
1
2
3
4
5
6
7
8
9
// fetchData.test.js
const fetchData = require('./fetchData');

test('fetchData returns data received', (done) => {
  fetchData((data) => {
    expect(data).toBe('data received');
    done(); // 调用 done() 告诉 Jest 测试已完成
  });
});

注意 如果 不调用 done(),Jest 可能会在异步代码执行前就结束测试,导致测试失败或假阳性结果。


2.2 测试返回 Promise 的异步函数

如果异步函数返回 Promise,可以直接返回这个 Promise,Jest 会等待它完成。

示例:返回 Promise

1
2
3
4
5
6
7
// fetchDataPromise.js
function fetchDataPromise() {
  return new Promise((resolve) => {
    setTimeout(() => resolve('data received'), 1000);
  });
}
module.exports = fetchDataPromise;
1
2
3
4
5
6
7
8
// fetchDataPromise.test.js
const fetchDataPromise = require('./fetchDataPromise');

test('fetchDataPromise resolves with data received', () => {
  return fetchDataPromise().then((data) => {
    expect(data).toBe('data received');
  });
});

这里直接 return fetchDataPromise(),Jest 会等到 Promise 解析后 才会结束测试。


2.3 测试使用 async/await 的异步代码

Jest 也支持 async/await,可以让异步测试代码更加简洁。

示例:使用 async/await

1
2
3
4
5
6
7
// fetchDataAsync.js
async function fetchDataAsync() {
  return new Promise((resolve) => {
    setTimeout(() => resolve('data received'), 1000);
  });
}
module.exports = fetchDataAsync;
1
2
3
4
5
6
7
// fetchDataAsync.test.js
const fetchDataAsync = require('./fetchDataAsync');

test('fetchDataAsync resolves with data received', async () => {
  const data = await fetchDataAsync();
  expect(data).toBe('data received');
});
  • test() 函数前加 async,然后使用 await 等待 fetchDataAsync() 解析。
  • Jest 会自动等待 await 语句完成,不需要手动调用 done()

2.4 测试异步代码的错误处理

如果异步代码可能会 reject,可以使用 catchrejects 来测试错误情况。

示例:测试 Promise reject

1
2
3
4
5
6
7
// fetchDataError.js
function fetchDataError() {
  return new Promise((_, reject) => {
    setTimeout(() => reject(new Error('network error')), 1000);
  });
}
module.exports = fetchDataError;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// fetchDataError.test.js
const fetchDataError = require('./fetchDataError');

// 方式 1:使用 `.catch`
test('fetchDataError rejects with error', () => {
  return fetchDataError().catch((error) => {
    expect(error).toEqual(new Error('network error'));
  });
});

// 方式 2:使用 Jest 提供的 `.rejects`
test('fetchDataError rejects with error', () => {
  return expect(fetchDataError()).rejects.toThrow('network error');
});

// 方式 3:使用 `async/await`
test('fetchDataError rejects with error using async/await', async () => {
  await expect(fetchDataError()).rejects.toThrow('network error');
});

总结

  • .rejects.toThrow('network error') 专门用于测试 Promise 失败的情况
  • 优先使用 async/await,让测试代码更简洁
  • 使用 done() 仅用于回调函数,避免滥用
  • 测试 Promise 失败时,用 .rejects.toThrow()
  • 始终 return Promise,确保 Jest 正确等待异步测试完成
This post is licensed under CC BY 4.0 by the author.