jest 单元测试
jest 默认检测规则
- 默认检测一:jest 默认检测任意__tests__目录下的所有文件,其内部的所有文件(无论命名)都会被当作测试文件执行
- 默认检测二:test.js 或者 spec.js 结尾的所有文件
集成 jest
shell
# 初始化
mkdir jest-demo
cd jest-demo
npm init -y
# 安装 jest
pnpm add jest -D
# 配置 package.json
{
"name": "jest-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^29.7.0"
}
}
# 新建入口文件 index.js
内容可为空
# 新建脚本文件 src/math.js
const add = (a,b) => a + b
const subtract = (a,b) => a - b;
const multiply = (a,b) => a * b
const divide = (a,b) => {
if (b === 0) {
throw new Error("除数不能为零");
}
return a / b;
}
module.exports = { add, subtract, multiply, divide };
# 新建测试文件 __tests__/math.test.js
const { add, subtract, multiply, divide } = require('../src/math.js');
describe('math.js 的测试', () => {
test('add 函数应该正确计算两个数字的和', () => {
expect(add(2, 3)).toBe(5);
expect(add(-1, 1)).toBe(0);
expect(add(0, 0)).toBe(0);
});
test('subtract 函数应该正确计算两个数字的差', () => {
expect(subtract(5, 3)).toBe(2);
});
test('multiply 函数应该正确计算两个数字的积', () => {
expect(multiply(4, 5)).toBe(20);
});
test('divide 函数应该正确计算两个数字的商', () => {
expect(divide(10, 2)).toBe(5);
});
test('divide 函数在除数为零时应该抛出错误', () => {
expect(() => { divide(10, 0); }).toThrow();
expect(() => { divide(10, 0); }).toThrow("除数不能为零");
});
});
# 测试
npm run test
# 结果
PASS __tests__/math.test.js
math.js 的测试
✓ add 函数应该正确计算两个数字的和 (3 ms)
✓ subtract 函数应该正确计算两个数字的差
✓ multiply 函数应该正确计算两个数字的积 (1 ms)
✓ divide 函数应该正确计算两个数字的商
✓ divide 函数在除数为零时应该抛出错误 (5 ms)
Test Suites: 1 passed, 1 total
Tests: 5 passed, 5 total
Snapshots: 0 total
Time: 0.212 s, estimated 1 s
Ran all test suites.jest 常见 API
shell
# 测试 API
describe('描述',()=>{}) 块用于将相关的测试用例分组
test('描述',()=>{}) 块定义一个具体的测试用例
expect(断言内容) 是断言的开始
# 常用匹配器
## 相等性判断
toBe(value): 使用 Object.is 来判断严格相等。适用于基本类型。
toEqual(value): 递归检查对象或数组的每个字段。适用于引用类型。
## 布尔值判断
toBeTruthy(): 判断是否为真值 (truthy)
toBeFalsy(): 判断是否为假值 (falsy)
## 数字判断
toBeGreaterThan(number): 大于
toBeGreaterThanOrEqual(number): 大于等于
toBeLessThan(number): 小于
toBeLessThanOrEqual(number): 小于等于
toBeCloseTo(number, numDigits): 用于浮点数比较,避免精度问题。
## 字符串判断
toMatch(regexpOrString): 判断字符串是否匹配正则表达式或子字符串
## 数组判断
toContain(item): 判断数组是否包含某个元素异步测试
- 回调函数测试
shell
# src/fetchData.js
function fetchData(callback) {
setTimeout(() => {
callback('peanut butter');
}, 1000);
}
module.exports = fetchData;
# __tests__/fetchData.test.js
const fetchData = require('./fetchData');
test('fetchData 应该通过回调函数返回 "peanut butter"', (done) => { # 测试异步代码时,需要在 test 函数中接收一个 done 参数
function callback(data) {
try {
expect(data).toBe('peanut butter');
done(); # 必须调用 done() 来告诉 Jest 测试已经完成
} catch (error) {
done(error); # 如果测试失败,把错误传给 done()
}
}
fetchData(callback);
});- Promise 测试
shell
# src/fetchDataPromise.js
function fetchDataPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('peanut butter');
# reject(new Error('出错了'));
}, 1000);
});
}
module.exports = fetchDataPromise;
# __tests__/fetchDataPromise.test.js
const fetchDataPromise = require('./fetchDataPromise');
test('fetchDataPromise 应该返回一个 resolved 的 Promise,其值为 "peanut butter"', () => { # 测试 Promise 时,需要让 test 函数返回这个 Promise
return fetchDataPromise().then(data => { # Jest 会等待 Promise resolve,如果 Promise reject,测试会失败
expect(data).toBe('peanut butter');
});
});
test('fetchDataPromise 应该返回一个 rejected 的 Promise', () => {
return expect(fetchDataPromise()).rejects.toThrow('出错了'); # 对于期望 reject 的 Promise,可以使用 .rejects
});- async/await 测试
shell
# src/fetchDataPromise.js
function fetchDataPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('peanut butter');
# reject(new Error('出错了'));
}, 1000);
});
}
module.exports = fetchDataPromise;
# __tests__/fetchDataPromise.test.js
const fetchDataPromise = require('./fetchDataPromise');
test('使用 async/await 测试 Promise', async () => {
const data = await fetchDataPromise();
expect(data).toBe('peanut butter');
});
test('使用 async/await 测试 rejected Promise', async () => {
await expect(fetchDataPromise()).rejects.toThrow('出错了');
});