Skip to content

jest 单元测试

jest 默认检测规则

  1. 默认检测一:jest 默认检测任意__tests__目录下的所有文件,其内部的所有文件(无论命名)都会被当作测试文件执行
  2. 默认检测二: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): 判断数组是否包含某个元素

异步测试

  1. 回调函数测试
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);
});
  1. 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
});
  1. 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('出错了');
});