XieYang-blog

jest学习笔记

本笔记根据jest官方文档23.6而来,根据个人理解,整合官网零散的文档并提炼了jest入门常用的内容到本笔记,以备后续使用和查阅!因个人能力有限,如有缺陷,请海涵!也欢迎您提出宝贵的意见。
本文使用yarn来管理npm包,如需npm或其他方式,请自行查阅相关文档。

开始使用之前的准备和配置

安装

npm

1
npm install --save-dev jest

yarn

1
yarn add --dev jest

全局安装来使用 CLI
yarn global add jest
使用 CLI 对 my-test 文件进行测试
jest my-test –notify –config=config.json
–config 使用config.json 作为一个配置文件。
–notify 在运行完成后显示一个原生的操作系统通知。
更多CLI信息请参阅

初始化

1
jest --init

在根目录生成一个基本的配置文件 jest.config.js

配合babel和react,如未使用则跳过此处

babel 7.0 以前版本

1
yarn add --dev babel-jest babel-core regenerator-runtime

然后在 .babelrc 文件做如下配置:

1
2
3
{
"presets": ["env", "react"]
}

babel 7.0及以后版本

1
yarn add --dev babel-jest babel-core@^7.0.0-bridge.0 @babel/core regenerator-runtime

然后在 .babelrc 文件做如下配置:

1
2
3
4
5
6
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}

注意:

如果您使用选项 {“modules”:false} 关闭了ES6模块的转换,则必须确保在测试环境中启用此功能。

1
2
3
4
5
6
7
8
9
// .babelrc
{
"presets": [["env", {"modules": false}], "react"],
"env": {
"test": {
"presets": [["env"], "react"]
}
}
}

当你安装 Jest 时,babel-jest 是会被自动安装的,并且如果你的项目下存在一个 Babel 配置文件时,它将会自动对相关文件进行转义。 如果要避免这个行为,你可以显式的重置 transform 配置项:

1
2
3
4
5
6
// package.json
{
"jest": {
"transform": {}
}
}

匹配器(matchers

普通匹配器

1
2
3
4
// 精准(exact)匹配 调用的Object.is 
test('two plus two is four', () => {
expect(2 + 2).toBe(4);
});
1
2
3
4
5
6
// 匹配对象的值是否相等,请使用 toEqual() 代替 toBe()
test('object assignment', () => {
const data = {one: 1};
data['two'] = 2;
expect(data).toEqual({one: 1, two: 2});
});

expect(2 + 2) 返回一个“期望对象(expect Object)”
toBe(4) 和 toEqual() 是匹配器,toEqual()会递归检查对象或数组的每个字段

1
2
3
4
5
6
7
8
// 取反的匹配 not.toBe()
test('adding positive numbers is not zero', () => {
for (let a = 1; a < 10; a++) {
for (let b = 1; b < 10; b++) {
expect(a + b).not.toBe(0);
}
}
});

Truthiness

toBeNull 只匹配 null
toBeUndefined 只匹配 undefined
toBeDefined 与 toBeUndefined 相反
toBeTruthy 匹配任何 if 语句为真
toBeFalsy 匹配任何 if 语句为假

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
test('null', () => {
const n = null;
expect(n).toBeNull();
expect(n).toBeDefined();
expect(n).not.toBeUndefined();
expect(n).not.toBeTruthy();
expect(n).toBeFalsy();
});

test('zero', () => {
const z = 0;
expect(z).not.toBeNull();
expect(z).toBeDefined();
expect(z).not.toBeUndefined();
expect(z).not.toBeTruthy();
expect(z).toBeFalsy();
});

数字

1
2
3
4
5
6
7
8
9
10
11
test('two plus two', () => {
const value = 2 + 2;
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3.5);
expect(value).toBeLessThan(5);
expect(value).toBeLessThanOrEqual(4.5);

// toBe and toEqual are equivalent for numbers
expect(value).toBe(4);
expect(value).toEqual(4);
});
1
2
3
4
5
6
// 对于比较浮点数相等,使用 toBeCloseTo 而不是 toEqual,因为你不希望测试取决于一个小小的舍入误差。
test('两个浮点数字相加', () => {
const value = 0.1 + 0.2;
//expect(value).toBe(0.3); 这句会报错,因为浮点数有舍入误差
expect(value).toBeCloseTo(0.3); // 这句可以运行
});

字符串

1
2
3
4
5
6
7
8
// toMatch(正则表达式)
test('there is no I in team', () => {
expect('team').not.toMatch(/I/);
});

test('but there is a "stop" in Christoph', () => {
expect('Christoph').toMatch(/stop/);
});

数组

1
2
3
4
5
6
7
8
9
10
11
const shoppingList = [
'diapers',
'kleenex',
'trash bags',
'paper towels',
'beer',
];

test('购物清单(shopping list)里面有啤酒(beer)', () => {
expect(shoppingList).toContain('beer');
});

例外

如果你想要测试的特定函数抛出一个错误,在它调用时,使用 toThrow。

1
2
3
4
5
6
7
8
9
10
11
12
function compileAndroidCode() {
throw new ConfigError('you are using the wrong JDK');
}

test('compiling android goes as expected', () => {
expect(compileAndroidCode).toThrow();
expect(compileAndroidCode).toThrow(ConfigError);

// You can also use the exact error message or a regexp
expect(compileAndroidCode).toThrow('you are using the wrong JDK');
expect(compileAndroidCode).toThrow(/JDK/);
});

匹配器的完整列表,请查阅参考文档

测试异步代码

在JavaScript中执行异步代码是很常见的。 当你有以异步方式运行的代码时,Jest 需要知道当前它测试的代码是否已完成,然后它可以转移到另一个测试。 Jest有若干方法处理这种情况。

回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 错误写法
test('the data is peanut butter', () => {
function callback(data) {
expect(data).toBe('peanut butter');
}

fetchData(callback);
});

// 正确写法
test('the data is peanut butter', done => {
function callback(data) {
expect(data).toBe('peanut butter');
done();
}

fetchData(callback);
});

如果 done()永远不会调用,这个测试将失败,这也是你所希望发生的。

Promises

从您的测试返回一个 Promise, Jest 会等待这一 Promise 来解决。 如果 Promise 被拒绝,则测试将自动失败。

1
2
3
4
5
6
7
8
test('the data is peanut butter', () => {
expect.assertions(1);

// fetchData,返回值是应该解析为字符串 'peanut butter' 的 Promise
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});

一定要返回 Promise - 如果你省略 return 语句,您的测试将在 fetchData 完成之前完成。

如果你想要 Promise 被拒绝,使用 .catch 方法。 请确保添加 expect.assertions 来验证一定数量的断言被调用。 否则一个fulfilled态的 Promise 不会让测试失败︰

1
2
3
4
test('the fetch fails with an error', () => {
expect.assertions(1);
return fetchData().catch(e => expect(e).toMatch('error'));
});

.resolves / .rejects

1
2
3
4
5
6
7
8
9
test('the data is peanut butter', () => {
expect.assertions(1);
return expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', () => {
expect.assertions(1);
return expect(fetchData()).rejects.toMatch('error');
});

Async/Await

1
2
3
4
5
6
7
8
9
10
11
12
13
14
test('the data is peanut butter', async () => {
expect.assertions(1);
const data = await fetchData();
expect(data).toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});

您可以将asyncawait.resolves.rejects结合起来

1
2
3
4
5
6
7
8
9
test('the data is peanut butter', async () => {
expect.assertions(1);
await expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
expect.assertions(1);
await expect(fetchData()).rejects.toMatch('error');
});

Setup and Teardown

写测试的时候你经常需要在运行测试前做一些准备工作,和在运行测试后进行一些整理工作。 Jest 提供辅助函数来处理这个问题。

为多次测试重复设置

如果你有一些要为多次测试重复设置的工作,你可以使用 beforeEach 和 afterEach。

例如,我们考虑一些与城市信息数据库进行交互的测试。 你必须在每个测试之前调用方法 initializeCityDatabase() ,同时必须在每个测试后,调用方法 clearCityDatabase()。 你可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
beforeEach(() => {
initializeCityDatabase();
});

afterEach(() => {
clearCityDatabase();
});

test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});

beforeEach 和 afterEach 能够通过与 异步代码测试 相同的方式处理异步代码——他们可以采取 done 参数或返回一个 promise。 例如,如果 initializeCityDatabase() 返回解决数据库初始化时的 promise ,我们会想返回这一 promise︰

1
2
3
beforeEach(() => {
return initializeCityDatabase();
});

一次性设置

在某些情况下,你只需要在文件的开头做一次设置。 当这种设置是异步行为时,可能非常恼人,你不太可能一行就解决它。 Jest 提供 beforeAll 和 afterAll 处理这种情况。

例如,如果 initializeCityDatabase 和 clearCityDatabase 都返回了 promise ,城市数据库可以在测试中重用,我们就能把我们的测试代码改成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
beforeAll(() => {
return initializeCityDatabase();
});

afterAll(() => {
return clearCityDatabase();
});

test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});

其他内容请参考官网文档

🐶 您的支持将鼓励我继续创作 🐶