前端单元测试(一) - 入门向

目录

  • 概述
    • 为何要写测试
    • 前端测试的类型
    • TDD vs BDD
  • 常用前端单元测试框架
    • Jest
    • Mocha
  • More
    • 前端测试该写些什么
    • 写什么都比没有开始好
  • 参考链接

概述

为何要写测试?

从自己的经验来说,在开发阶段,写测试能帮助自己对功能的实现,有一个较为全面的思考,并且降低后续修改引入 Bug 的几率。在交付之前,就能排除大量的 Bug。在后续测试,或需求变更的情况下,修改代码之后,可以保证不对已经稳定的功能引入新 Bug。从别人处接手项目时,也能大大避免因新接手人员对项目不熟悉,引入的新问题。
总体上来说,为自己的代码写测试,是一项首次繁琐、后续便利的工作,并且从长远来看,一个项目后续修改的频率要远远大于首次的构建和开发,不论对测试、开发、交接都是利大于弊的╮(╯_╰)╭。
这篇以本人入手时的体验,简单介绍前端测试的部分内容。

前端测试的类型

有一种关于测试的分类,称为前端测试金字塔,将前端测试从塔底到塔尖分为:

  • 单元测试(Unit Tests)
    顾名思义,对一个功能单元进行测试,如一个对日期进行格式化的方法。
    单元测试是非常细化和相对全面的,要保证一个单元代码的可靠性,需要尽可能地对所有情况编写测试脚本。
  • 快照测试(Snapshot Tests)
    快照测试是对 UI 组件渲染结果的测试。
    在 Jest 中,快照测试并不是对图片进行比对,而是保存渲染组件的标记,使得快照文件体积小,而测试速度快。
    更多关于 Jest snapshot test
  • 端到端测试(End to End Tests)
    是对模拟我们对项目的实际操作,测试过程较为复杂和繁琐,耗时长。

想了解更多关于这几种测试类型的细节,请看 前端测试金字塔

TDD vs BDD

测试驱动开发(TDD)是先写测试,根据测试的内容实现具体的功能代码,再用之前的测试进行验证。TDD 是用测试来推动功能的实现。
行为驱动开发(BDD)是从行为的角度来定义测试的内容,用自然语言描述测试用例。
有关于 TDD 和 BDD 的思考,可以参考 The Difference Between TDD and BDD

常用前端单元测试框架

常见的测试框架有 Jest,Mocha,Jasmine 等。
这里举例说明一下 Jest 和 Mocha。

Jest

  • 配置简单(开箱即用)
  • 自带断言库(在 Jest 中称为 matchers)
  • 内置的覆盖率(coverage)统计
  • 内置的快照功能
    Jest 由 Facebook 团队开发维护,故对于测试 React、ReactNative 项目支持友好。

使用

(来自官网的例子)
新建一个项目(npm init),新建一个 /src 目录和 /test 目录,用于存放功能代码和测试代码。
安装 Jest,无需额外配置:

npm install --save-dev jest
// or
yarn add --dev jest

完成后的目录如下:

/project
    -/node_modules
    -/src
    -/test

在 /src 文件目录下新建一个 sum.js 文件,

function sum(a, b) {
    return a + b;
}
module.exports = sum;

在 /test 中新建一个 sum.test.js 文件,引入 sum.js 的方法:

const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

在 package.json 的 scripts 中新增:

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

之后运行:

npm run test
// or
yarn test

就可以得到结果:

PASS  ./sum.test.js
✓ adds 1 + 2 to equal 3 (5ms)

上面例子中的“expect(sum(1, 2))”称为断言,在 Jest 中叫做“matchers”,Jest 提供了多种 API 满足不同的情况。
Jest 为每个测试文件预置了一些全局方法和对象,“test” 用来包裹一个最小的测试单元,一系列相关的测试单元可以用 “describe”包裹:

const myBeverage = {
  delicious: true,
  sour: false,
};

describe('my beverage', () => {
  test('is delicious', () => {
    expect(myBeverage.delicious).toBeTruthy();
  });

  test('is not sour', () => {
    expect(myBeverage.sour).toBeFalsy();
  });
});

Mocha

  • 配置自由灵活
  • 自行引入需要的断言库
  • 支持几种不同的测试代码的组织形式(包括 BDD、TDD 等)
  • 可运行在 Node 环境和浏览器
    Mocha 的有更高的自由度,更能配合需要高度定制化的项目,插件配置方面也能找到大量的参考信息。

使用

安装方式类似。
Mocha 需要自行引入断言库(即需要自行额外安装对应的库),在使用上,和 Jest 并没有太大区别:

var assert = require('assert')
describe('Array', function() {
  describe('#indexOf()', function() {
    it('should return -1 when the value is not present', function() {
      assert.equal([1,2,3].indexOf(4), -1)
    })
  })
})

可以直接运行:

./node_modules/mocha/bin/mocha

或者也在 package.json 中新增 scripts:

"scripts": {
    "test": "mocha"
}
...
npm test

Mocha 中 describe 是作为 BDD 的一种接口,它同时提供适用 TDD 的接口:suite(), test(), suiteSetup(), suiteTeardown(), setup(), and teardown()等:

suite('Array', function() {
  setup(function() {
    // ...
  });

  suite('#indexOf()', function() {
    test('should return -1 when not present', function() {
      assert.equal(-1, [1,2,3].indexOf(4));
    });
  });
});

除了 BDD、TDD,Mocha 还支持 Exports,QUnit,和 Require-style 接口,具体参考文档

More

前端测试该写些什么

刚开始接触入门前端测试时,最困扰我的就是测试到底该写什么了。
对 UI 进行测试的目的较为明确,只要根据页面需要达到的效果,对照着加入测试即可。但若进行单元测试,或者针对功能进行测试时,我们总是希望覆盖面能广一点、考虑的情况能全面一点,以达到更好的测试效果。不同的项目代码的功能、组织方式大相径庭,很难有一套通用的定论来指明我们的测试代码具体应该怎么写,但一些思考角度是可以分享和借鉴的。
以下是我针对一个功能型(或者说工具型)项目进行测试的几个方面:

  • 明确的功能点
    即需求方给的明确的需求,以及为了实现这些需求,需要达到的一些标准。
  • 输入值、输出值、边缘数据校验(特别是工具类型的单元)
    如输入值不符合标准的情况,输入值不符合标准的情况也可能存在多种情形,都需要分情况考虑。
  • 测试过程中出现 Bug 的情况
    即使在开发过程中通过测试规避了很多问题,但不可避免仍会有一些特定场景会引出 Bug,功能修复后添加针对该场景的测试脚本,可以规避该场景 Bug 的重复出现。

写什么都比没有开始好

对于不同的项目,需要侧重的测试方面也大不相同,真正开始思考如何全面地测试一个项目,并且转换成测试代码之后,能大大提升代码质量,提升代码的复用性、模块化划分、全面性。
从长远上来看也能显著提升大型项目的开发效率,特别是参与开发人员多、交接频繁、迭代频率高的项目。

Thanks.

其他参考

  • Jest
  • Mocha

你可能感兴趣的:(前端单元测试(一) - 入门向)