Jest生命周期方法全解析从入门到精通!

Jest 中的生命周期方法

在 Jest 测试框架中,生命周期方法用于在测试用例执行前后执行特定的操作。这些方法可以帮助你在测试前设置环境、清理资源等。Jest 提供了两类生命周期方法:

  • 重复性的生命周期方法
    • beforeEach
    • afterEach
  • 一次性的生命周期方法
    • beforeAll
    • afterAll

这些方法都是全局方法,无需引入,直接在测试文件中使用即可。

重复性的生命周期方法

beforeEachafterEach

beforeEachafterEach 方法会在每个测试用例的前后执行。这对于需要在每个测试用例之前设置初始状态或在每个测试用例之后清理资源非常有用。

示例代码
const {
    
     sum, sub, mul, div } = require("./tools");

// beforeEach 会在执行每一个测试用例之前被触发
beforeEach(() => {
    
    
  console.log("全局的beforeEach");
});

afterEach(() => {
    
    
  console.log("全局的afterEach");
});

test("测试加法函数", () => {
    
    
  const result = sum(1, 3);
  expect(result).toBe(4);
  console.log("\x1b[31m%s\x1b[0m", "测试加法函数");
});

test("测试减法函数", () => {
    
    
  const result = sub(15, 10);
  expect(result).toBe(5);
  console.log("\x1b[31m%s\x1b[0m", "测试减法函数");
});

test("测试乘法函数", () => {
    
    
  const result = mul(2, 3);
  expect(result).toBe(6);
  console.log("\x1b[31m%s\x1b[0m", "测试乘法函数");
});

test("测试除法函数", () => {
    
    
  const result = div(50, 2);
  expect(result).toBe(25);
  console.log("\x1b[31m%s\x1b[0m", "测试除法函数");
});

执行顺序

  • 每个测试用例执行前,先执行全局的 beforeEach
  • 测试用例执行完毕后,执行全局的 afterEach
    16816946204785

一次性的生命周期方法

beforeAllafterAll

beforeAllafterAll 方法分别在所有测试用例执行之前和之后执行一次。这对于需要在所有测试用例之前进行一次性设置或在所有测试用例之后进行一次性清理非常有用。

示例代码
// ...
// beforeAll 是在整个测试套件的第一个测试用例执行之前执行
beforeAll(() => {
    
    
  console.log("全局的beforeAll");
});

// afterAll 会在所有测试用例执行完成之后,然后再执行 afterAll
afterAll(() => {
    
    
  console.log("全局的afterAll");
});
// ...

执行顺序

  • 所有测试用例执行之前,先执行全局的 beforeAll
  • 所有测试用例执行完毕后,执行全局的 afterAll
    16816949683970

在分组中添加生命周期方法

如果测试用例较多,可以使用 describe 进行分组。在分组中也可以添加生命周期方法,这些方法仅对该组测试用例有效。

示例代码
// 第二组
describe("第二组", () => {
    
    
  beforeEach(() => {
    
    
    console.log("\x1b[34m%s\x1b[0m", "分组beforeEach");
  });

  afterEach(() => {
    
    
    console.log("\x1b[34m%s\x1b[0m", "分组afterEach");
  });

  beforeAll(() => {
    
    
    console.log("\x1b[32m%s\x1b[0m", "分组beforeAll");
  });

  afterAll(() => {
    
    
    console.log("\x1b[32m%s\x1b[0m", "分组afterAll");
  });

  test("测试乘法函数", () => {
    
    
    const result = mul(2, 3);
    expect(result).toBe(6);
    console.log("\x1b[31m%s\x1b[0m", "测试乘法函数");
  });

  test("测试除法函数", () => {
    
    
    const result = div(50, 2);
    expect(result).toBe(25);
    console.log("\x1b[31m%s\x1b[0m", "测试除法函数");
  });
});

16816973539011

执行顺序

  • 全局的 beforeAll 先执行。
  • 分组的 beforeAll 再执行。
  • 每个测试用例执行前,先执行全局的 beforeEach,再执行分组的 beforeEach
  • 每个测试用例执行完毕后,先执行分组的 afterEach,再执行全局的 afterEach
  • 所有测试用例执行完毕后,先执行分组的 afterAll,再执行全局的 afterAll

补充:test.only

test.only 用于只运行特定的测试用例。这对于调试失败的测试用例非常有用。

示例代码
test.only("测试乘法函数", () => {
    
    
  const result = mul(2, 3);
  expect(result).toBe(6);
  console.log("\x1b[31m%s\x1b[0m", "测试乘法函数");
});

执行顺序

  • 使用 test.only 时,只会执行标记的测试用例。
  • 对应的生命周期方法也会被执行。

源码解析

在 Jest 的源码中,这些生命周期方法的背后,实际上都是调用的同一个名为 _addHook 的方法。

const beforeEach: THook = (fn, timeout) =>
  _addHook(fn, 'beforeEach', beforeEach, timeout);
const beforeAll: THook = (fn, timeout) =>
  _addHook(fn, 'beforeAll', beforeAll, timeout);
const afterEach: THook = (fn, timeout) =>
  _addHook(fn, 'afterEach', afterEach, timeout);
const afterAll: THook = (fn, timeout) =>
  _addHook(fn, 'afterAll', afterAll, timeout);
const _addHook = (
  fn: Circus.HookFn,
  hookType: Circus.HookType,
  hookFn: THook,
  timeout?: number,
) => {
    
    
  const asyncError = new ErrorWithStack(undefined, hookFn);

  if (typeof fn !== 'function') {
    
    
    asyncError.message =
      'Invalid first argument. It must be a callback function.';

    throw asyncError;
  }

  dispatchSync({
    
     asyncError, fn, hookType, name: 'add_hook', timeout });
};

_addHook 方法主要负责错误处理,并调用 dispatchSync 方法来调度钩子函数的执行。

总结

  • Jest 中的生命周期方法分为重复性和一次性两种。
  • 重复性的生命周期方法:
    • beforeEach:每个测试用例前执行。
    • afterEach:每个测试用例后执行。
  • 一次性的生命周期方法:
    • beforeAll:所有测试用例前执行一次。
    • afterAll:所有测试用例后执行一次。
  • 在分组中可以添加局部的生命周期方法,但需注意与全局方法的执行顺序。
  • 使用 test.only 可以方便地运行单个测试用例,以便在调试失败的测试用例时进行测试。

猜你喜欢

转载自blog.csdn.net/weixin_53961451/article/details/143465833