Jest 写前端单元测试入门教程

写测试能减少 bug,提高代码质量。同时,重构测试覆盖率高的代码,不担心改坏以前的功能。

前端的测试可以分为 3 类:单元测试,集成测试 和 UI 测试。

  • 单元测试是对软件的最小单元进行测试。比如:一个函数,一个组件。

  • 集成测试,也叫组装测试或联合测试。在单元测试的基础上,将所有模块按照设计要求组装成为子系统或系统,进行测试。

  • UI 测试是对 UI 的呈现效果和交互进行测试。

本文主要介绍用 Jest[1] 来写单元测试。Jest 是一款优雅、简洁的 JavaScript 测试框架。下面的是用 Jest 写的单元测试:

import sum from './sum';

test('sum', () => {
  expect(sum(1, 2)).toBe(3);
  expect(sum(-1, -2)).toBe(-3);
});

sum 是要测试的函数。test(...) 是包裹了要测试的一个特性。expect(...) 是断言:期望 sum(1, 2) 的值是 3,如果 sum(1, 2) 的值不是 3,则该测试会失败。

Jest 主要包含 3 块内容:

  1. 安装。

  2. 运行。

  3. Jest API。

1 安装

Jest 是依赖 Node.js[2] 的。安装好 Node 后,初始化 node 项目:

npm init -y

安装 Jest

npm install --save-dev jest

支持 Babel

需要支持 ES6, ES7 等语法,则安装 Babel 相关依赖:

yarn add --dev babel-jest @babel/core @babel/preset-env

在项目根目录下创建 Babel 配置文件:babel.config.js 来配置与当前 Node 版本兼容的 Babel

module.exports = {
  presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
};

支持 TypeScript

yarn add --dev @babel/preset-typescript

在项目根目录下创建 TypeScript 配置文件:tsconfig.json 。内容类似:

{
  "compilerOptions": {
      "module": "commonjs",
      "noImplicitAny": true,
      "removeComments": true,
      "preserveConstEnums": true,
      "sourceMap": true,
      "esModuleInterop": true
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

2 运行

运行项目里的所有测试用例

需要在 package.json 中加如下内容:

{
  "scripts": {
    "test": "jest"
  }
}

测试用例要写在单独的文件,而不是放在要测试的文件里。测试用例的文件名需要带 .spec.[js|ts].test.[js|ts]。比如,一个文件叫 sum.js,对其进行测试,一般在该文件的相同目录下,创建个测试用例文件 sum.spec.js

执行 npm run test 即可运行项目中,就会运行所有的测试用例。

运行特定的一个测试用例文件

在项目根目录行执行 yarn jest 测试用例文件路径npm run test 测试用例文件路径

运行特定的一个测试用例

只需将要运行用例的 test(...) 改成 test.only(...),然后再运行该测试用例文件。类似的,运行一组用例,把 describe(...) 改成 describe.only(...)

获取测试覆盖率

测试覆盖率(test coverage) 衡量的是功能代码被测试用例覆盖的比率。对代码质量要求高的项目,会要求测试覆盖率在 90% 以上。

获取测试覆盖率的命令:

jest --coverage

3 Jest API

断言 API

编写测试时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设。比如:

expect(2 + 2).toBe(4)

Jest 支持主要断言API如下:

6e252b59f60a99f6c106934555da64af.png


所有的断言API见:这里[3]

Jest 场景

测试异步代码

处理异步一般有 3 种方式:回调, PromiseAsync/Await

回调

业务代码:

function fetchNameCallback(cb: (name: string) => void) {
    setTimeout(() => {
      cb('Joel');
    }, 1000)
}

用例代码如下:

test('async: callback', done => {
  fetchNameCallback(name => {
    expect(name).toBe('Joel');
    done(); // 通知 Jest,回调结束了
  });
});

注意:异步回调结束后,需要调用参数 done。以此来通知 Jest,回调结束了。

Promise

业务代码:

function fetchName(throwError?: boolean) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if(!throwError) {
        resolve('Joel')
      } else {
        reject('error happened')
      }
    }, 1000)
  });
}

用例代码如下:

test('async: Promise', () => {
  fetchName().then(name => {
    expect(name).toBe('Joel');
  });
  //  异常处理
  fetchName(true).catch(e => {
    expect(e).toMatch('error');
  });
});
Async/Await

业务代码和上面的 Promise 的相同。

用例代码如下:

test.only('Async/Await', async () => {
  const name = await fetchName();
  expect(name).toBe('Joel');
  // 异常处理
  try {
    fetchName(true);
  } catch(e) {
    expect(e).toMatch('error');
  }
});

测试前的准备操作和测试后的整理操作

写测试的时候可能需要在测试前做一些准备工作。运行测试后,需要做进行一些整理工作。用 Jest 这么写:

每次用例的前后都执行
// 前
beforeEach(() => {
});

// 后
afterEach(() => {
});
所有用例的前后执行
beforeAll(() => {
});

afterAll(() => {
});

只会被执行一次。

Mock 外部依赖

我们在测试模块功能时,如果模块对外部的依赖的是有问题的,也会导致测试的不通过。为规避这种问题,会 Mock外部依赖:用一个不出错的实现来代替外部依赖。

Mock 第三方包的部分 api

这边以 Mock axios[4] 为例,业务代码:

axiosFetchUser = () => {
  return axios.get('/user');
}

测试代码:

test('fetch user', () => {
  axios.get.mockImplementation(url => {
    if(/^\/user$/.test(url)) {
      return Promise.resolve({name: 'Joel'})
    }
    return Promise.resolve('other')
  })

  axiosFetchUser().then(({ name }) => {
    expect(name).toBe('Joel');
  })
});

其中 axios.get.mockImplementation(...) Mock了 axios.get 的实现。

Mock 某个文件的部分内容

我们有个工具函数文件 utils.ts,内容如下:

const guid = () => ...;
export default guid;

export const getYear = () => ...;
export const getMonth = () => ...;

我们只 Mock 上面文件中的 guidgetYear,其他部分保持原状。这么写:

jest.mock('./util', () => {
  const originalModule = jest.requireActual('./util');
  return {
    __esModule: true,
    ...originalModule,
    default: () => 'abc', // mock guid
    getYear: () => 2021,
  };
});

Mock 完整的第三方包和文件

Mock 完整的第三方包和文件只需做 2 步。

  1. __mocks__/ 下建 Mock 的文件。

  2. 通知 Jest 用 Mock 的实现:jest.mock('./moduleName')jest.mock('module_name')

详细介绍见: 这里[5]

最后

行动起来,开始练习写单元测试吧~

参考资料

[1]

Jest: https://jestjs.io/

[2]

Node.js: https://nodejs.org/en/

[3]

这里: https://jestjs.io/zh-Hans/docs/expect

[4]

axios: https://axios-http.com/

[5]

这里: https://jestjs.io/zh-Hans/docs/manual-mocks

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Jest 是一个流行的 JavaScript 测试框架,可以用于编单元测试、集成测试和端到端测试。下面是 Jest 单元测试入门的步骤: 1. 安装 Jest 使用 npm 安装 Jest:`npm install --save-dev jest` 2. 编测试用例 在项目根目录下创建一个名为 `__tests__` 的文件夹,并在其中创建一个名为 `example.test.js` 的文件。在 `example.test.js` 文件中编测试用例: ```javascript describe('示例测试', () => { test('测试1', () => { expect(1 + 1).toBe(2); }); test('测试2', () => { expect(true).toBeTruthy(); }); }); ``` 上面的代码定义了一个测试套件 `示例测试`,其中包含两个测试用例 `测试1` 和 `测试2`。每个测试用例都是一个函数,其中包含一个或多个 `expect` 语句,用于断言测试结果是否符合预期。 3. 运行测试 在命令行中输入 `npx jest` 命令,Jest 将自动查找项目中的测试用例并运行它们。如果所有测试用例都通过,Jest 将输出一个绿色的提示。 4. 高级配置 Jest 提供了丰富的配置选项,可以用于定制测试过程。例如,可以在 `package.json` 文件中添加以下配置: ```json { "jest": { "testEnvironment": "node", "testMatch": [ "**/__tests__/**/*.test.js" ], "coverageThreshold": { "global": { "branches": 80, "functions": 80, "lines": 80, "statements": 80 } } } } ``` 上面的配置指定了测试环境为 Node.js,测试文件必须位于 `__tests__` 文件夹中,并以 `.test.js` 结尾。还指定了代码覆盖率的阈值,如果代码覆盖率低于指定的阈值,Jest 将会提示测试失败。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值