专栏名称: freeCodeCamp
FreeCodeCamp.cn官方公众号
目录
相关文章推荐
哔哩哔哩  ·  45岁后,女性要知道的健康知识 ·  2 天前  
哔哩哔哩  ·  从农村女孩到人民教师 ·  2 天前  
51好读  ›  专栏  ›  freeCodeCamp

前端测试框架 Jest

freeCodeCamp  · 公众号  ·  · 2017-08-16 12:33

正文

前端测试工具一览

前端测试工具也和前端的框架一样纷繁复杂,其中常见的测试工具,大致可分为测试框架、断言库、测试覆盖率工具等几类。在正式开始本文之前,我们先来大致了解下它们:

测试框架

测试框架的作用是提供一些方便的语法来描述测试用例,以及对用例进行分组。

测试框架可分为两种: TDD (测试驱动开发)和 BDD (行为驱动开发),我理解两者间的区别主要是一些语法上的不同,其中 BDD 提供了提供了可读性更好的用例语法,至于详细的区别可参见 The Difference Between TDD and BDD 一文。

常见的测试框架有 Jasmine , Mocha 本文要介绍的 Jest

断言库

断言库主要提供语义化方法,用于对参与测试的值做各种各样的判断。这些语义化方法会返回测试的结果,要么成功、要么失败。常见的断言库有 Should.js , Chai.js 等。

测试覆盖率工具

用于统计测试用例对代码的测试情况,生成相应的报表,比如 istanbul

Jest

为什么选择 Jest

Jest 是 Facebook 出品的一个测试框架,相对其他测试框架,其一大特点就是就是内置了常用的测试工具,比如自带断言、测试覆盖率工具,实现了开箱即用。

而作为一个面向前端的测试框架, Jest 可以利用其特有的 快照测试 功能,通过比对 UI 代码生成的快照文件,实现对 React 等常见框架的自动测试。

此外, Jest 的测试用例是并行执行的,而且只执行发生改变的文件所对应的测试,提升了测试速度。目前在 Github 上其 star 数已经破万;而除了 Facebook 外,业内其他公司也开始从其它测试框架转向 Jest ,比如 Airbnb 的尝试 ,相信未来 Jest 的发展趋势仍会比较迅猛。

安装

Jest 可以通过 npm 或 yarn 进行安装。以 npm 为例,既可用npm install -g jest进行全局安装;也可以只局部安装、并在 package.json 中指定 test 脚本:

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

Jest 的测试脚本名形如*.test.js,不论 Jest 是全局运行还是通过npm test运行,它都会执行当前目录下所有的*.test.js 或 *.spec.js 文件、完成测试。

基本使用

用例的表示

表示测试用例是一个测试框架提供的最基本的 API , Jest 内部使用了 Jasmine 2 来进行测试,故其用例语法与 Jasmine 相同。test()函数来描述一个测试用例,举个简单的例子:

// hello.js
module.exports = () => 'Hello world'

// hello.test.js
let hello = require('hello.js')

test('should get "Hello world"', () => {
    expect(hello()).toBe('Hello world') // 测试成功
// expect(hello()).toBe('Hello') // 测试失败
})

其中toBe('Hello world')便是一句断言( Jest 管它叫 “matcher” ,想了解更多 matcher 请参考 文档 。写完了用例,运行在项目目录下执行npm test,即可看到测试结果:

若测试失败,会标识出失败的断言位置,结果如下:

用例的预处理或后处理

有时我们想在测试开始之前进行下环境的检查、或者在测试结束之后作一些清理操作,这就需要对用例进行预处理或后处理。对测试文件中所有的用例进行统一的预处理,可以使用 beforeAll() 函数;而如果想在每个用例开始前进行都预处理,则可使用 beforeEach() 函数。至于后处理,也有对应的 afterAll() 和 afterEach() 函数。

如果只是想对某几个用例进行同样的预处理或后处理,可以将先将这几个用例归为一组。使用 describe() 函数即可表示一组用例,再将上面提到的四个处理函数置于 describe() 的处理回调内,就实现了对一组用例的预处理或后处理:

describe('test testObject', () => {
    beforeAll(() => {
// 预处理操作
    })

    test('is foo', () => {
       expect(testObject.foo).toBeTruthy()
    })

    test('is not bar', () => {
        expect(testObject.bar).toBeFalsy()
    })

    afterAll(() => {
// 后处理操作
    })
})

测试异步代码

异步代码的测试,关键点在于告知测试框架测试何时完成,让其在恰当的时机进行断言。针对几种常见的异步代码形式, Jest 也提供了相应的异步测试语法。首先对于异步回调,向其传入并执行 done 函数, Jest 会等 done 回调执行结束后,结束测试:

// asyncHello.js
module.exports = (name, cb) => setTimeout(() => cb(`Hello ${name}`), 1000)

// asyncHello.test.js
let asyncHello = require('asyncHello.js')

test('should get "Hello world"', (done) => {
    asyncHello('world', (result) => {
        expect(result).toBe('Hello world')
        done()
    })
})

此外,对于 Promise 控制的异步代码,可以直接在 then 回调中进行断言,只要保证在用例中返回该 Promise 对象即可:

// promiseHello.js
module.exports = (name) => {
return new Promise((resolve) => {
        setTimeout(() => resolve(`Hello ${name}`), 1000)
    })
}

// promiseHello.test.js
let promiseHello = require('promiseHello.js')

it('should get "Hello world"', () => {
    expect.assertions(1); // 确保至少有一个断言被调用,否则测试失败
return promiseHello('world').then((data) => {
        expect(data).toBe('Hello world')
    })
})

Jest 也支持 async/await 语法的测试,无需多余的操作,只要在 await 后进行断言即可,和同步测试的写法一致。

测试覆盖率

Jest 内置了测试覆盖率工具 istanbul ,要开启,可以直接在命令中添加 --coverage 参数,或者在 package.json 文件进行更详细的 配置

运行 istanbul 除了会再终端展示测试覆盖率情况,还会在项目下生产一个 coverage 目录,内附一个测试覆盖率的报告,让我们可以清晰看到分支的代码的测试情况。比如下面这个例子:

// branches.js
module.exports = (name) => {
if (name === 'Levon') {
return `Hello Levon`
    } else {
return `Hello ${name}`
    }
}

// branches.test.js
let branches = require('../branches.js')

describe('Multiple branches test', ()=> {
    test('should get Hello Levon', ()=> {
          expect(branches('Levon')).toBe('Hello Levon')
    });
// test('should get Hello World', ()=> {
//       expect(branches('World')).toBe('Hello World')
// });  
})

运行 jest --coverage 可看到生产的报告里展示了代码的覆盖率和未测试的行数:

如果我们把branches.test.js中的注释去掉,跑遍测试对象中的所有分支,测试覆盖率就是100%了:

在前端项目中使用

搭配React和其它框架







请到「今天看啥」查看全文