测试框架 Jest 实用教程

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6


官网 ​​https://jestjs.io/docs/getting-started​

安装

cnpm i --save-dev jest

使用

  1. 在项目中的任意位置(通常单独建个名为 test 的文件夹)新建以 ​​.test.js​​ 为后缀的测试文件,如 ​​expect.test.js​​ (若项目中有 test.js 存在,请改为其他名称,JEST 会将 test.js 也视为测试文件)
  2. 在 package.json 中添加测试脚本
"scripts": {
"test": "jest",

则执行 npm run test 时,便会使用 jest 执行所有的 ​​.test.js​​ 为后缀的测试文件

  1. ​expect.test.js​​ 中添加内容
test("断言2+2=4", () => {
expect(2 + 2).toBe(4);
});

以上即一个测试案例,用于断言 2+2=4
此处的 test 也可以用 it

  1. 执行 npm run test
    vscode中可以直接点击脚本执行按钮

    效果如下:

    全部绿色,即测试通过。

若想测试一直执行,可以使用

npx jest 测试文件名称 --watch

断言

相等 toBe

expect(2 + 2).toBe(4);

执行的是 ES6 的Object.is,与严格相等运算符(===)基本一致,不会进行强制类型转换,不同之处为 +0不等于-0,NaN等于自身,对引用类型的数据(如对象、数组等),比较其地址是否相同。

相等 toEqual

会比较数组/对象的每一项,但会忽略 undefined

// 测试通过
test("toEqual断言对象相等", () => {
expect({ a: 1 }).toEqual({ a: 1, b: undefined });
});

严格相等 toStrictEqual

与 toEqual 类似,但不会忽略 undefined

// 测试报错
test("toStrictEqual断言对象相等", () => {
expect({ a: 1 }).toStrictEqual({ a: 1, b: undefined });
});

不相等 not

在判断相等前添加 not 即可

test("断言2+3不等于4", () => {
expect(2 + 3).not.toBe(4);
});

特殊值的断言

  • toBeNull() 断言为 null
  • toBeUndefined() 断言为 undefined
  • toBeTruthy() 断言为 true
  • toBeFalsy() 断言为 false

比较

  • toBeGreaterThan(3) 大于3
  • toBeGreaterThanOrEqual(3.5) 大于等于3.5
  • toBeLessThan(5) 小于5
  • toBeLessThanOrEqual(4.5) 小于等于4.5

浮点数的计算结果比较 toBeCloseTo

因 js 无法精确计算浮点数,不能用 toBe ,而要用 toBeCloseTo

test('断言 0.1+0.2=0.3', () => {
const value = 0.1 + 0.2;
//expect(value).toBe(0.3); 此方式会断言失败
expect(value).toBeCloseTo(0.3);
});

字符串包含 toMatch

// Christoph 中包含 stop
expect('Christoph').toMatch(/stop/);

数组中查找指定项 toContain

expect(shoppingList).toContain('milk');

更多断言用法见 ​​https://jestjs.io/docs/expect#expectvalue​

异步测试

回调函数

const callbackFunc = (cb) => {
setTimeout(() => {
cb("hello");
}, 100);
};

test("callback", (done) => {
callbackFunc((data) => {
//等待异步执行
done();
expect(data).toBe("hello");
});
});

Promise

const promiseFuc = () => Promise.resolve("hello");

test("promise", () => {
return promiseFuc().then((data) => {
expect(data).toBe("hello");
});
});

await 写法

const promiseFuc = () => Promise.resolve("hello");

test("await async", async () => {
const data = await promiseFuc();
expect(data).toBe("hello");
});

属性 resolves 写法

const promiseFuc = () => Promise.resolve("hello");

test("resolves", () => {
return expect(promiseFuc()).resolves.toBe("hello");
});

属性 rejects 写法

const promiseFuc = () => Promise.reject("error");

test("rejects", () => {
return expect(promiseFuc()).rejects.toBe("error");
});

模拟 mock

模拟数据

function mockTestFunc(cb) {
return cb(3);
}

test("mock", () => {
// jest.fn() 是对 mock 过程的监听
const mockCB = jest.fn();
// 调用mock函数
mockTestFunc(mockCB);
// 测试mock函数是否执行
expect(mockCB).toHaveBeenCalled();
// 测试mock函数回调的参数是否为3
expect(mockCB).toHaveBeenCalledWith(3);
// 测试mock函数回调的次数是否为1
expect(mockCB).toHaveBeenCalledTimes(1);
// 打印mock对象,可查看相关属性
console.log(mockCB.mock);
});

打印内容为:

{
calls: [ [ 3 ] ],
contexts: [ undefined ],
instances: [ undefined ],
invocationCallOrder: [ 1 ],
results: [ { type: 'return', value: undefined } ],
lastCall: [ 3 ]
}

上例中没有对回调的参数进行二次处理,所以 value 为 undefined
jest.fn() 中可以对回调的参数进行二次处理,得到对应的值 value

function mockTestFunc(cb) {
return cb(3);
}

test("mock二次处理", () => {
// jest.fn() 是对 mock 过程的监听
const mockCB = jest.fn((x) => x * 2);
// 调用mock函数
mockTestFunc(mockCB);
// 打印mock对象,可查看相关属性
console.log(mockCB.mock);
});

打印结果为:

{
calls: [ [ 3 ] ],
contexts: [ undefined ],
instances: [ undefined ],
invocationCallOrder: [ 1 ],
results: [ { type: 'return', value: 6 } ],
lastCall: [ 3 ]
}

得到值 value 为 6

模拟第三方库

真实请求如下:
user.js

const axios = require("axios");

module.exports = function getUserName(id) {
return axios
.get(`https://jsonplaceholder.typicode.com/users/${id}`)
.then((res) => {
return res.data.username;
});
};

mock.test.js

const getUserName = require("./user.js");

test("真实请求第三方库-axios", () => {
return getUserName(1).then((name) => {
console.log(name);
});
});
mock 写法1
const getUserName = require("./user.js");
const axios = require("axios");
jest.mock("axios");

axios.get.mockImplementation(() => {
return Promise.resolve({
data: {
username: "朝阳",
},
});
});

test("mock 第三方库-axios", () => {
return getUserName(1).then((name) => {
console.log(name);
});
});

此时的 mockCB 即 axios.get ,可以进行监听

test("mock 第三方库-axios", () => {
return getUserName(1).then((name) => {
// 监听 axios.get 是否被调用
expect(axios.get).toHaveBeenCalled();
});
});
mock 写法2

使用 mockResolvedValue 直接模拟 Promise 的返回值。

axios.get.mockResolvedValue({
data: {
username: "朝阳",
},
});
mock 写法3 【推荐】

项目目录下新建文件夹 ​​__mocks__​​​,在​​__mocks__​​​文件夹中按模拟的第三方库名称新建 js 文件,如 ​​axios.js​​,内容为

const axios = {
get: jest.fn(() => Promise.resolve({ data: { username: "朝阳" } })),
};

module.exports = axios;

如此,则测试文件中的 axios 请求,都会按 axios.js 中逻辑执行。

const getUserName = require("./user.js");

test("mock 第三方库-axios", () => {
return getUserName(1).then((name) => {
console.log(name);
});
});

会打印 朝阳

时间控制

执行所有定时器

const callbackFunc = (cb) => {
setTimeout(() => {
cb("hello");
}, 1000);
};

test("回调是否执行", () => {
const callback = jest.fn();
callbackFunc(callback);
// 测试 callback 是否执行
expect(callback).toHaveBeenCalled();
});

此处因 setTimeout 导航回调函数 1秒后 执行,所以测试会报错
解决方案是通过 jest 接管时间控制,修正后代码如下(详见备注):

//  jest 接管时间控制
jest.useFakeTimers();

test("回调是否执行", () => {
const callback = jest.fn();
callbackFunc(callback);
// 执行所有定时器
jest.runAllTimers();
expect(callback).toHaveBeenCalled();
});

分步执行定时器

// setTimeout的嵌套:1秒后调用 one ,再过2秒后调用 two
const callbackFunc = (cb) => {
setTimeout(() => {
cb("one");
setTimeout(() => {
cb("two");
}, 2000);
}, 1000);
};

// jest 接管时间控制
jest.useFakeTimers();

test("回调是否执行", () => {
const callback = jest.fn();
callbackFunc(callback);
// 执行一个定时器
jest.runOnlyPendingTimers();
expect(callback).toHaveBeenLastCalledWith("one");
// 又执行一个定时器
jest.runOnlyPendingTimers();
expect(callback).toHaveBeenLastCalledWith("two");
});

指定代码运行的时间

jest.advanceTimersByTime(代码执行时间),单位为毫秒

const callbackFunc = (cb) => {
setTimeout(() => {
cb("one");
}, 1000);
};

// jest 接管时间控制
jest.useFakeTimers();

test("回调是否执行", () => {
const callback = jest.fn();
callbackFunc(callback);
// 500毫秒后
jest.advanceTimersByTime(500);
// 1秒后才会执行,测试报错!
expect(callback).toHaveBeenLastCalledWith("one");
});

再增加 500 ms 即可

test("回调是否执行", () => {
const callback = jest.fn();
callbackFunc(callback);
// 500毫秒后
jest.advanceTimersByTime(500);
// 再次500毫秒后
jest.advanceTimersByTime(500);
// 测试通过!
expect(callback).toHaveBeenLastCalledWith("one");
});


阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“测试框架 Jest 实用教程” 的相关文章