前端自动化测试框架Jest中的钩子函数及作用域

发表于:2022-5-30 09:16

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:三年没洗澡    来源:掘金

#
Jest
  Jest 中的钩子函数
  通常,在编写测试时,你需要在测试运行之前进行一些初始化工作,并且需要在测试运行之后进行一些完成工作。Jest提供了钩子函数来处理这个问题。
  我们通过一个 计数器 来学习钩子函数相关的知识。
  首先在index.js里面定义一个类,并且导出:
// index.js

class Counter {
  constructor() {
    this.number = 0;
  }
  add() {
    this.number++;
  }
  minus() {
    this.number--;
  }
}

export default Counter;

  可以看到,这是一个使用 ES6 语法定义的 class:
  在实例化的时候定义了number,初始值是0
  定义了静态方法add,执行结果为number加1
  定义了静态方法minus,执行结果为number减1
  然后在index.test.js里面引入这个类,测试add方法:
// index.test.js

import Counter from "./index";

const counter = new Counter();

test("测试 Counter 的 add 方法", () => {
  expect(counter.number).toBe(0);
  counter.add();
  expect(counter.number).toBe(1);
});

  然后运行测试用例,完美通过。
  然后继续添加minus方法的测试用例:
// index.test.js

import Counter from "./index";

const counter = new Counter();

test("测试 Counter 的 add 方法", () => {
  expect(counter.number).toBe(0);
  counter.add();
  expect(counter.number).toBe(1);
});

test("测试 Counter 的 minus 方法", () => {
  expect(counter.number).toBe(0);
  counter.minus();
  expect(counter.number).toBe(-1);
});

  然后运行测试用例,结果为:
  测试 add 方法:通过
  测试 minus 方法:不通过
  出现这个情况的原因是:
  我们的实例化过程写在了测试用例外面,所有的测试用例公用一个counter 实例,所以在测试 add 方法的时候,我们已经对实例的number属性做出了修改。导致minus方法的测试用例没用通过。
  解决办法是:
  我们可以把实例化写在每一个测试用例里面,每次测试都创建一个新的counter 实例。这样就不会公用一个counter了,也不会影响到其它实例了。
  但是一般情况下,我们不会这样做,因为测试用例很多的话,每次都创建一个 counter实例 是一件很麻烦的事情,假如当前文件中有1000个和counter有关的测试用例,那么就要创建1000次counter实例。
  这个时候!钩子函数派上用场了!
// index.test.js

import Counter from "./index";

let counter = null;

beforeEach(() => {
  counter = new Counter();
});

test("测试 counter 的 add 方法", () => {
  expect(counter.number).toBe(0);
  counter.add();
  expect(counter.number).toBe(1);
});

test("测试 counter 的 minus 方法", () => {
  expect(counter.number).toBe(0);
  counter.minus();
  expect(counter.number).toBe(-1);
});

  然后运行测试用例,结果通过。
  beforeEach() 的作用是在每个测试用例执行之前执行里面的回调函数,如果你需要在测试开始之前对很多个测试做一些重复的工作,比如要初始化状态,你就可以使用它。
  实际上,Jest 一共有四个钩子函数:
  beforeAll:在所有测试用例执行之前调用(调用一次)
  afterAll:在所有测试用例执行之后调用(调用一次)
  beforeEach:在每个测试用例执行之前调用(调用多次)
  afterEach:在每个测试用例执行之后调用(调用多次)

  钩子函数的作用域
  在了解作用域之前,需要先了解一个小知识点:Scoping
  默认情况下,beforeAll和afterAll应用于文件中的每个测试用例。
  实际上,还可以使用describe方法将测试用例进行分组。当它们位于describe中时,beforeAll和afterAll只应用于当前分组中的测试用例。
// index.test.js

describe("测试分组1", () => {
  beforeAll(() => {
    console.log("测试分组1 - beforeAll");
  });
  afterAll(() => {
    console.log("测试分组1 - afterAll");
  });
  test("测试", () => {
    console.log("测试分组1 测试");
    expect(1 + 1).toBe(2);
  });
});

describe("测试分组2", () => {
  beforeAll(() => {
    console.log("测试分组2 - beforeAll");
  });
  afterAll(() => {
    console.log("测试分组2 - afterAll");
  });
  test("测试", () => {
    console.log("测试分组2 测试");
    expect(1 + 1).toBe(2);
  });
});

  执行上面代码:

  在默认情况下,Jest将按照describe的顺序连续运行所有测试分组,等待每个测试完成后再继续。
  需要注意的是:
  如果我们不进行分组,相当于在最外面写了一层describe。
  除此之外,实际上,在describe里面还能嵌套describe,就像下面这样:
// index.test.js

describe("第一层", () => {
  beforeAll(() => console.log("第一层 - beforeAll"));
  describe("第二层", () => {
    beforeAll(() => console.log("第二层 - beforeAll"));
    describe("第三层", () => {
      beforeAll(() => console.log("第三层 - beforeAll"));
      test("测试", () => {
        console.log("测试");
        expect("hello" + " " + "world").toBe("hello world");
      });
    });
  });
});

  运行这个测试,可以看到下面结果:

  所以可以得出一些结论:
  每一个 describe 都可以有自己的钩子函数
  每一个 describe 都有自己的作用域
  每一个 钩子函数也有自己的作用域,就是当前所在的 describe
  每一个 describe 里面的钩子函数对自己作用域下面所有的测试用例都生效
  如果 describe 是多层嵌套的,那么测试用例执行的顺序是由外到内
  最后再补充一个知识点:
  如果有·、多个测试用例,但是只想运行一个的时候,注释掉其它的测试用例往往不是最好的选择,我们可以使.only语法去执行:
// index.test.js

test.only("这个测试会被执行", () => {
  expect("A").toBe("A");
});

test("这个测试会被跳过", () => {
  expect("B").toBe("B");
});

  这样就可以单独运行一个测试用例,其它测试会被跳过。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号