(清清嗓子,拿起麦克风)
嘿,大家好!欢迎来到今天的“JS 自动化测试实践”小课堂。我是今天的讲师,大家可以叫我老码。今天咱们不搞那些虚头巴脑的概念,直接上手,把 Jest
和 Vitest
这两个测试界的当红炸子鸡玩个明明白白,顺便聊聊单元测试和快照测试那些事儿。
开场白:为什么要搞自动化测试?
在开始之前,先问大家一个问题:谁没被 Bug 搞崩溃过?(台下一片举手声)
OK,看来大家都深有体会。手动测试效率低、容易出错、还特别枯燥,简直是程序员的噩梦。自动化测试就像一个不知疲倦的机器人,帮你一遍又一遍地检查代码,提前发现 Bug,让你有更多的时间摸鱼…啊不,是优化代码,提升用户体验。
第一部分:Jest 初体验:你的第一个单元测试
Jest
是 Facebook 出品的,特点是配置简单、功能强大,号称“零配置”就能上手。虽然“零配置”有点夸张,但确实比很多测试框架要方便得多。
1. 安装 Jest
首先,我们需要安装 Jest
:
npm install --save-dev jest
# 或者
yarn add --dev jest
2. 编写被测函数
假设我们有一个简单的函数,用来计算两个数的和:
// src/sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
3. 编写测试用例
接下来,我们编写测试用例来验证这个函数是否正确:
// test/sum.test.js
const sum = require('../src/sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
test('adds -1 + 2 to equal 1', () => {
expect(sum(-1, 2)).toBe(1);
});
describe
: 用于组织测试用例,可以将相关的测试用例放在同一个describe
块中,方便管理和阅读。test
: 一个测试用例,它接受一个字符串描述和一个函数,函数中包含断言。expect
: 用于创建断言,它接受一个值作为参数,并返回一个对象,该对象包含各种匹配器。toBe
: 一个匹配器,用于比较两个值是否相等。
4. 配置 package.json
在 package.json
文件中添加一个 test
脚本:
{
"scripts": {
"test": "jest"
}
}
5. 运行测试
现在,我们可以运行测试了:
npm test
# 或者
yarn test
如果一切顺利,你应该会看到类似这样的输出:
PASS test/sum.test.js
✓ adds 1 + 2 to equal 3 (5ms)
✓ adds -1 + 2 to equal 1 (1ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.714s
恭喜你!你已经成功运行了你的第一个 Jest
单元测试。
第二部分:Jest 进阶:更多匹配器和异步测试
Jest
提供了丰富的匹配器,可以满足各种测试需求。
常用匹配器:
匹配器 | 描述 | 示例 |
---|---|---|
toBe |
比较两个值是否相等(使用 === ) |
expect(1 + 1).toBe(2); |
toEqual |
比较两个对象或数组是否相等(递归比较) | expect({ a: 1 }).toEqual({ a: 1 }); |
toBeNull |
检查值是否为 null |
expect(null).toBeNull(); |
toBeUndefined |
检查值是否为 undefined |
expect(undefined).toBeUndefined(); |
toBeDefined |
检查值是否已定义 | expect(1).toBeDefined(); |
toBeTruthy |
检查值是否为真值(truthy) | expect(true).toBeTruthy(); |
toBeFalsy |
检查值是否为假值(falsy) | expect(false).toBeFalsy(); |
toBeGreaterThan |
检查值是否大于另一个值 | expect(2).toBeGreaterThan(1); |
toBeLessThan |
检查值是否小于另一个值 | expect(1).toBeLessThan(2); |
toBeCloseTo |
比较浮点数是否接近另一个值,避免精度问题 | expect(0.1 + 0.2).toBeCloseTo(0.3); |
toContain |
检查数组或字符串是否包含某个元素或子字符串 | expect([1, 2, 3]).toContain(2); |
toMatch |
检查字符串是否匹配正则表达式 | expect('hello').toMatch(/llo/); |
toThrow |
检查函数是否抛出异常 | expect(() => { throw new Error(); }).toThrow(); |
not |
用于取反匹配器 | expect(1 + 1).not.toBe(3); |
异步测试:
很多时候,我们需要测试异步函数,比如 Promise
或者 async/await
。Jest
提供了几种方式来处理异步测试。
1. 使用 Promise
:
// src/fetchData.js
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('peanut butter');
}, 100);
});
}
module.exports = fetchData;
// test/fetchData.test.js
const fetchData = require('../src/fetchData');
test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});
注意:需要在测试用例中返回 Promise
,Jest
会等待 Promise
resolve 或 reject。
2. 使用 async/await
:
// test/fetchData.test.js
const fetchData = require('../src/fetchData');
test('the data is peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});
使用 async/await
可以使异步测试代码更简洁易读。
3. 使用 resolves
和 rejects
:
// test/fetchData.test.js
const fetchData = require('../src/fetchData');
test('the data is peanut butter', () => {
return expect(fetchData()).resolves.toBe('peanut butter');
});
test('the fetch fails with an error', () => {
return expect(fetchData()).rejects.toThrow('error'); // 假设 fetchData 在出错时抛出 'error'
});
resolves
和 rejects
可以更方便地测试 Promise
的 resolve 和 reject 情况。
第三部分:Vitest 闪亮登场:更快更轻量级的选择
Vitest
是一个由 Vite 驱动的单元测试框架。如果你已经在使用 Vite 构建项目,那么 Vitest
可以无缝集成,带来更快的测试速度和更好的开发体验。
1. 安装 Vitest
npm install --save-dev vitest
# 或者
yarn add --dev vitest
2. 配置 Vitest
在 vite.config.js
文件中添加 test
配置:
// vite.config.js
import { defineConfig } from 'vite';
export default defineConfig({
test: {
// 在这里配置 Vitest
},
});
3. 编写测试用例
Vitest
的 API 和 Jest
非常相似,所以你可以直接使用 Jest
的语法来编写测试用例:
// test/sum.test.js
import { describe, expect, it } from 'vitest';
import sum from '../src/sum';
describe('sum', () => {
it('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
it('adds -1 + 2 to equal 1', () => {
expect(sum(-1, 2)).toBe(1);
});
});
注意:Vitest
使用 import
语句来导入模块,而不是 require
。
4. 运行测试
在 package.json
文件中添加一个 test
脚本:
{
"scripts": {
"test": "vitest"
}
}
然后运行测试:
npm test
# 或者
yarn test
Vitest
最大的优势在于它的速度。由于它使用了 Vite 的底层技术,因此测试速度非常快,尤其是在大型项目中,可以显著提升开发效率。
第四部分:快照测试:你的 UI 卫士
快照测试是一种非常有用的测试技术,它可以帮助你检测 UI 组件是否发生了意外的变化。
1. 什么是快照?
快照就是一个 UI 组件在特定状态下的渲染结果的文本表示。当你第一次运行快照测试时,Jest
或 Vitest
会生成一个快照文件,并将 UI 组件的渲染结果保存到文件中。
2. 快照测试的原理
在后续的测试中,Jest
或 Vitest
会将 UI 组件的当前渲染结果与快照文件进行比较。如果两者不一致,测试就会失败,提示你 UI 组件发生了变化。
3. 快照测试的用途
- 检测 UI 组件是否发生了意外的变化。
- 验证 UI 组件的渲染结果是否符合预期。
- 跟踪 UI 组件的变化历史。
4. Jest 中的快照测试
// src/Button.js
import React from 'react';
function Button({ children }) {
return <button>{children}</button>;
}
export default Button;
// test/Button.test.js
import React from 'react';
import { render } from '@testing-library/react';
import Button from '../src/Button';
test('renders a button with text', () => {
const { asFragment } = render(<Button>Click me</Button>);
expect(asFragment()).toMatchSnapshot();
});
@testing-library/react
:一个用于测试 React 组件的库。render
:用于渲染 React 组件。asFragment
:返回一个包含渲染结果的 Fragment。toMatchSnapshot
:将渲染结果与快照文件进行比较。
第一次运行测试时,Jest
会生成一个快照文件:test/__snapshots__/Button.test.js.snap
,内容如下:
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders a button with text 1`] = `
<DocumentFragment>
<button>
Click me
</button>
</DocumentFragment>
`;
如果修改了 Button
组件的渲染逻辑,再次运行测试时,测试就会失败,提示你快照文件与当前渲染结果不一致。
5. Vitest 中的快照测试
Vitest
的快照测试 API 与 Jest
非常相似:
// test/Button.test.js
import React from 'react';
import { render } from '@testing-library/react';
import Button from '../src/Button';
import { expect, it } from 'vitest'; // 引入 Vitest 的 expect 和 it
it('renders a button with text', () => {
const { asFragment } = render(<Button>Click me</Button>);
expect(asFragment()).toMatchSnapshot();
});
6. 快照测试的最佳实践
- 只对 UI 组件进行快照测试,不要对业务逻辑进行快照测试。
- 定期更新快照文件,以反映 UI 组件的变化。
- 在代码审查中仔细检查快照文件的变化。
第五部分:Jest 和 Vitest 的选择:鱼与熊掌?
特性 | Jest | Vitest |
---|---|---|
易用性 | 配置简单,上手容易 | 配置相对简单,但需要了解 Vite 的配置 |
速度 | 较慢 | 非常快,尤其是在大型项目中 |
集成度 | 与各种工具和框架集成良好 | 与 Vite 集成无缝,对其他框架支持较好,但可能需要额外配置 |
功能 | 功能强大,提供了丰富的匹配器和 API | 功能完善,API 与 Jest 相似,学习成本低 |
社区支持 | 庞大的社区,丰富的资源和插件 | 社区活跃,但相对较小 |
如何选择?
- 如果你已经在使用 Vite 构建项目,并且追求更快的测试速度,那么 Vitest 是一个不错的选择。
- 如果你需要更成熟的测试框架,并且需要与各种工具和框架集成,那么 Jest 仍然是首选。
当然,你也可以同时使用 Jest
和 Vitest
。例如,你可以使用 Jest
进行集成测试,使用 Vitest
进行单元测试。
总结:
自动化测试是保证代码质量的关键环节。Jest
和 Vitest
都是优秀的 JavaScript 测试框架,它们可以帮助你编写可靠的测试用例,提前发现 Bug,提升开发效率。希望今天的课程能够帮助大家更好地理解和应用自动化测试。
(放下麦克风,鞠躬)
谢谢大家!大家可以提问了!