Jest 基础:describe 和 it/test 块、expect 和匹配器、setup 和 teardown 函数
好,咱们进入 Jest 的核心地带。说实话,Jest 的 API 并不多,但每个都挺讲究。我刚开始用 Jest 时,总觉得它跟别的测试框架差不多,用着用着才发现——嗯,细节里藏着不少好东西。
describe 和 it/test 块:测试的组织方式
先说说 describe。它就是个分组工具,把相关的测试用例归到一起。我个人习惯这样用:
describe('计算器模块', () => {
describe('加法功能', () => {
it('应该正确计算两个正数相加', () => {
expect(add(1, 2)).toBe(3);
});
it('应该正确处理负数', () => {
expect(add(-1, -2)).toBe(-3);
});
});
describe('减法功能', () => {
it('应该正确计算两个正数相减', () => {
expect(subtract(5, 3)).toBe(2);
});
});
});
你想想看,describe 可以嵌套。外层描述模块,内层描述具体功能。这样跑测试时,控制台输出的信息特别清晰。
至于 it 和 test,它们完全等价。我更喜欢用 it,因为读起来更像自然语言——「it should do something」。当然,你用 test 也没问题,纯粹是个人偏好。
expect 和匹配器:断言的艺术
expect 是 Jest 的断言入口。它返回一个「期望对象」,然后你调用各种「匹配器」来做判断。说白了,就是「我期望这个值怎么样」。
常用的匹配器我列一下:
| 匹配器 | 用途 | 示例 |
|---|---|---|
toBe() |
严格相等(===) | expect(1 + 1).toBe(2) |
toEqual() |
深度相等(对象/数组) | expect({a: 1}).toEqual({a: 1}) |
toBeTruthy() |
判断是否为真值 | expect('hello').toBeTruthy() |
toBeFalsy() |
判断是否为假值 | expect(0).toBeFalsy() |
toContain() |
数组/字符串是否包含 | expect([1,2,3]).toContain(2) |
toThrow() |
是否抛出异常 | expect(() => fn()).toThrow() |
这里有个坑,我踩过。用 toBe 比较对象:
// 这样会失败!
expect({ a: 1 }).toBe({ a: 1 });
// 应该用 toEqual
expect({ a: 1 }).toEqual({ a: 1 });
为什么会这样?因为 toBe 用的是 ===,两个对象引用不同。而 toEqual 会递归比较每个字段。记住这个区别,能省不少调试时间。
toBeCloseTo() 代替。
setup 和 teardown 函数:测试的准备工作
写测试时,经常需要做一些「前置工作」和「收尾工作」。Jest 提供了四个钩子函数:
beforeEach:每个测试用例执行前运行afterEach:每个测试用例执行后运行beforeAll:所有测试用例执行前运行一次afterAll:所有测试用例执行后运行一次
看个实际例子:
describe('用户管理', () => {
let userDb;
beforeAll(() => {
// 只做一次,比如连接数据库
userDb = new Database();
});
beforeEach(() => {
// 每个测试前清空数据,保证隔离
userDb.clear();
});
afterEach(() => {
// 每个测试后记录日志
console.log('测试完成');
});
afterAll(() => {
// 关闭数据库连接
userDb.close();
});
it('应该能创建用户', () => {
userDb.create({ name: '张三' });
expect(userDb.count()).toBe(1);
});
it('应该能删除用户', () => {
userDb.create({ name: '李四' });
userDb.delete('李四');
expect(userDb.count()).toBe(0);
});
});
我在项目中遇到过一个问题:测试之间互相影响。后来发现是 beforeEach 里忘了重置某个全局状态。从那以后,我养成了习惯——每个测试用例都假设「世界是干净的」。
作用域:钩子函数的执行顺序
这里有个细节,很多人会搞混。钩子函数的作用域跟 describe 块有关:
describe('外层', () => {
beforeEach(() => console.log('外层 beforeEach'));
describe('内层', () => {
beforeEach(() => console.log('内层 beforeEach'));
it('测试用例', () => {
console.log('执行测试');
});
});
});
// 输出顺序:
// 外层 beforeEach
// 内层 beforeEach
// 执行测试
说白了,Jest 会从外到内执行所有 beforeEach,然后执行测试,再按从内到外的顺序执行 afterEach。这个机制很实用——外层做通用准备,内层做特定准备。
嗯,以上就是 Jest 测试的基础骨架。掌握了 describe、it、expect 和钩子函数,你就能写出结构清晰、隔离良好的测试用例了。下一章咱们会深入异步测试,那才是真正考验功底的地方。