基础语法

基础语法

我们从一个基本的 Math 模块开始。首先创建一个 math.js 文件:

// basic/math.js

const sum = (a, b) => a + b;
const mul = (a, b) => a * b;
const sub = (a, b) => a - b;
const div = (a, b) => a / b;

export { sum, mul, sub, div };

要测试这个 Math 模块是否正确,我们需要编写测试代码。通常,测试文件与所要测试的源码文件同名,但是后缀名为 .test.js 或者 .spec.js。我们这里则创建一个 math.test.js 文件:

// basic/math.test.js

import { sum, mul, sub, div } from "./math";

test("Adding 1 + 1 equals 2", () => {
  expect(sum(1, 1)).toBe(2);
});

test("Multiplying 1 * 1 equals 1", () => {
  expect(mul(1, 1)).toBe(1);
});

test("Subtracting 1 - 1 equals 0", () => {
  expect(sub(1, 1)).toBe(0);
});

test("Dividing 1 / 1 equals 1", () => {
  expect(div(1, 1)).toBe(1);
});

执行 npm test jest 将会执行所有匹配的测试文件,并最终返回测试结果。

匹配器

匹配器用来实现断言功能。在前面的例子中,我们只使用了 toBe() 匹配器:

test("Adding 1 + 1 equals 2", () => {
  expect(sum(1, 1)).toBe(2);
});

在此代码中,expect(sum(1, 1)) 返回一个“期望”对象,.toBe(2) 是匹配器。匹配器将 expect() 的结果(实际值)与自己的参数(期望值)进行比较。当 Jest 运行时,它会跟踪所有失败的匹配器,并打印出错误信息。

常用的匹配器如下:

  • toBe 使用 Object.is 判断是否严格相等。
  • toEqual 递归检查对象或数组的每个字段。
  • toBeNull 只匹配 null
  • toBeUndefined 只匹配 undefined
  • toBeDefined 只匹配非 undefined
  • toBeTruthy 只匹配真。
  • toBeFalsy 只匹配假。
  • toBeGreaterThan 实际值大于期望。
  • toBeGreaterThanOrEqual 实际值大于或等于期望值
  • toBeLessThan 实际值小于期望值。
  • toBeLessThanOrEqual 实际值小于或等于期望值。
  • toBeCloseTo 比较浮点数的值,避免误差。
  • toMatch 正则匹配。
  • toContain 判断数组中是否包含指定项。
  • .toHaveProperty(keyPath, value) 判断对象中是否包含指定属性。
  • toThrow 判断是否抛出指定的异常。
  • toBeInstanceOf 判断对象是否是某个类的实例,底层使用 instanceof

所有的匹配器都可以使用 .not 取反:

test("Adding 1 + 1 does not equal 3", () => {
  expect(1 + 1).not.toBe(3);
});
复制代码;

对于 Promise 对象,我们可以使用 .resolves.rejects

// .resolves
test("resolves to lemon", () => {
  // make sure to add a return statement
  return expect(Promise.resolve("lemon")).resolves.toBe("lemon");
});

// .rejects
test("rejects to octopus", () => {
  // make sure to add a return statement
  return expect(Promise.reject(new Error("octopus"))).rejects.toThrow(
    "octopus"
  );
});

钩子函数

Jest 为我们提供了四个测试用例的钩子:beforeAll()、afterAll()、beforeEach()、afterEach()。beforeAll() 和 afterAll() 会在所有测试用例之前和所有测试用例之后执行一次。beforeEach() 和 afterEach() 会在每个测试用例之前和之后执行。

describe

我们可以使用 describe 将测试用例分组,在 describe 块中的钩子函数只作用于块内的测试用例:

beforeAll(() => console.log("1 - beforeAll")); // 1
afterAll(() => console.log("1 - afterAll")); // 12
beforeEach(() => console.log("1 - beforeEach")); // 2,6
afterEach(() => console.log("1 - afterEach")); // 4,10
test("", () => console.log("1 - test")); // 3

describe("Scoped / Nested block", () => {
  beforeAll(() => console.log("2 - beforeAll")); // 5
  afterAll(() => console.log("2 - afterAll")); // 11
  beforeEach(() => console.log("2 - beforeEach")); // 7
  afterEach(() => console.log("2 - afterEach")); // 9
  test("", () => console.log("2 - test")); // 8
});

需要注意的是,顶级的 beforeEach 会在 describe 块内的 beforeEach 之前执行。Jest 会先执行 describe 块内的操作,等 describe 块内的操作执行完毕后,按照出现在 describe 中的先后顺序执行测试用例,因此初始化和销毁操作应该放在钩子函数中运行,而不是 describe 块内:

describe("outer", () => {
  console.log("describe outer-a"); // 1

  describe("describe inner 1", () => {
    console.log("describe inner 1"); // 2
    test("test 1", () => {
      console.log("test for describe inner 1"); // 6
      expect(true).toEqual(true);
    });
  });

  console.log("describe outer-b"); // 3

  test("test 1", () => {
    console.log("test for describe outer"); // 7
    expect(true).toEqual(true);
  });

  describe("describe inner 2", () => {
    console.log("describe inner 2"); // 4
    test("test for describe inner 2", () => {
      console.log("test for describe inner 2"); // 8
      expect(false).toEqual(false);
    });
  });

  console.log("describe outer-c"); // 5
});

jest-when

jest-when 允许你使用一组原始的 Jest mock 函数,以便只根据你的 mock 函数被调用的参数来训练你的 mock。

import { when } from "jest-when";

const fn = jest.fn();
when(fn).calledWith(1).mockReturnValue("yay!");

expect(fn(1)).toEqual("yay!");

when(fn)
  .calledWith(1)
  .mockReturnValue("yay!")
  .calledWith(2)
  .mockReturnValue("nay!");

expect(fn(1)).toEqual("yay!");
expect(fn(2)).toEqual("nay!");
上一页
下一页