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),我们将立即处理
权威发布,测试选择不纠结!第15届软件测试行业报告,直击行业发展,把握未来方向!