???? 令人愉快的 JavaScript 测试

栏目: JavaScript · 发布时间: 6年前

内容简介:Jest 是 Facebook 发布的一个开源的、基于 Jasmine 框架的 JavaScript 单元测试工具。提供了包括内置的测试环境 DOM API 支持、断言库、Mock 库等,还包含了 Snapshot Testing、 Instant Feedback 等特性。它自动集成了断言、JSDom、覆盖率报告等开发者所需要的所有测试工具,是一款几乎零配置的测试框架。并且它对同样是 Facebook 的开源前端框架 React 的测试十分友好。测试框架的作用是提供一些方便的语法来描述测试用例,以及对用
???? 令人愉快的 JavaScript 测试

1.1 Jest 是什么?

Jest 是 Facebook 发布的一个开源的、基于 Jasmine 框架的 JavaScript 单元测试工具。提供了包括内置的测试环境 DOM API 支持、断言库、Mock 库等,还包含了 Snapshot Testing、 Instant Feedback 等特性。它自动集成了断言、JSDom、覆盖率报告等开发者所需要的所有测试工具,是一款几乎零配置的测试框架。并且它对同样是 Facebook 的开源前端框架 React 的测试十分友好。

1.2 谁在用?

???? 令人愉快的 JavaScript 测试

1.3 卖点

  • Jest 是 Facebook 出品的一个测试框架,相对其他测试框架,其一大特点就是就是内置了常用的测试工具,比如自带断言、测试覆盖率工具,实现了开箱即用。
  • 而作为一个面向前端的测试框架, Jest 可以利用其特有的快照测试功能,通过比对 UI 代码生成的快照文件,实现对 React 等常见框架的自动测试。
  • 此外, Jest 的测试用例是并行执行的,而且只执行发生改变的文件所对应的测试,提升了测试速度。目前在 Github 上其 star 数已经破万;而除了 Facebook 外,业内其他公司也开始从其它测试框架转向 Jest ,比如 Airbnb 的尝试 ,相信未来 Jest 的发展趋势仍会比较迅猛。

2 课前准备

2.1 测试框架

测试框架的作用是提供一些方便的语法来描述测试用例,以及对用例进行分组。 测试框架可分为两种: TDD (测试驱动开发)和 BDD (行为驱动开发),我理解两者间的区别主要是一些语法上的不同,其中 BDD 提供了提供了可读性更好的用例语法,至于详细的区别可参见 The Difference Between TDD and BDD - Josh Davis 一文。 常见的测试框架有 Jasmine, Mocha 以及本文要介绍的 Jest 。

2.2 断言库

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

测试覆盖率工具

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

3 上手

初始化一个项目

mkidr $CODE_PATH && cd $CODE_PATH
npm init -y
npm i -D jest
复制代码

:warning: jest 默认不支持es6 如果需要测试es6 需要额外安装

npm i -D babel-jest babel-core babel-preset-env

并且增加 .babelrc 配置如下:

{
  "presets": ["env"]
}
复制代码

package.json 添加测试脚本

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watchAll"
  }
}
复制代码

这样我们的食材就准备好了:v:

3.1 第一个例子:chestnut: 1+2 = 3 让我们从写一个两个数相加的示例函数开始。首先,创建 sum.js sum.test.js 文件︰

touch sum.js sum.test.js
code .
复制代码

::sum.js::

export default function sum(a, b) {
  return a + b
}
复制代码

::sum.test.js::

import sum from './sum'
test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3)
})
复制代码

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

运行 npm run test

???? 令人愉快的 JavaScript 测试

以上是官网的一个小例子

3.2 新的尝试

你可以修改下 函数 sum 试试错误的结果

::sum.js::

export default function sum(a, b) {
  return a + b + 1
}
复制代码

运行 npm run test

???? 令人愉快的 JavaScript 测试

测试没通过:broken_heart:,如果我们学会了使用jest 那我们的工作流程将会变成:

需求分析 :arrow_right: 写单元测试 :arrow_right: 写代码 :arrow_right: 单元测试全部通过

那么就意味着单元测试全部通过就没bug了么?那可不一定

???? 令人愉快的 JavaScript 测试
那么为什么要写单元测试?详见写单元测试的重要性

4 常用的几个Jest断言

接下来写一个函数的集合 ::functions.js::和::functions.test.js::来演示一些常用的测试方法

touch functions.js functions.test.js
复制代码

::functions.js::

export default {
  add: (num1, num2) => num1 + num2,
}
复制代码

::functions.test.js::

import functions from './functions'
const { add } = functions
// toBe
test('Adds 2 + 2 to equal 4', () => {
  expect(add(2, 2)).toBe(4)
})
复制代码

4.1 not

在::functions.test.js::增加测试

...
// not
test('Adds 2 + 2 to NOT equal 5', () => {
  expect(functions.add(2, 2)).not.toBe(5);
});
...
复制代码

.not 修饰符允许你测试结果不等于某个值的情况,这和英语的语法几乎完全一样,很好理解。

4.2 toBeNull

::functions.js::

export default {
  add: (num1, num2) => num1 + num2,
	isNull: () => null
}
复制代码

在::functions.test.js::增加测试

// toBeNull
test('Should be null', () => {
  expect(isNull()).toBeNull();
});
复制代码

测试通过

4.3 toBeFalsy

toBeFalsy 判断值是否为false

// toBeFalsy
test('Should be falsy', () => {
  expect(undefined).toBeFalsy()
})
复制代码

4.4 toBeFalsy/toBe

// functions.js
createUser: () => {
  const user = { firstName: 'Brad' };
  user['lastName'] = 'Traversy';
  return user;
}
// functions.test.js
test('User should be Brad Traversy object', () => {
  expect(createUser()).toEqual({
    firstName: 'Brad',
    lastName: 'Traversy'
  });
});
复制代码

:warning: .toEqual 匹配器会递归的检查对象所有属性和属性值是否相等,所以如果要进行应用类型的比较时,请使用 .toEqual 匹配器而不是 .toBe

4.5 More

jest 使用的断言风格与社区相差无几。

// 数值对比
expect(8).toBeGreaterThan(7)
expect(7).toBeGreaterThanOrEqual(7)
expect(6).toBeLessThan(7)
expect(6).toBeLessThanOrEqual(6)

// Regex 正则匹配
expect('team').not.toMatch(/I/i)

// Arrays
expect(['john', 'karen', 'admin']).toContain('admin');
复制代码

更多断言方法参见:Expect · Jest

4.6 测试异步

JSONPlaceholder是一个提供免费的在线 REST API 的网站,我们在开发时可以使用它提供的 url 地址测试下网络请求以及请求参数。或者当我们程序需要获取一些假数据、假图片时也可以使用它。

// functions.js
fetchUser: () =>
	axios
    .get('https://jsonplaceholder.typicode.com/users/1')
    .then(res => res.data)
// functions.test.js
// Async Await
test('User fetched name should be Leanne Graham', async () => {
  expect.assertions(1)
  const data = await functions.fetchUser()
  expect(data.name).toEqual('Leanne Graham')
})
复制代码

上面我们调用了expect.assertions(1),它能确保在异步的测试用例中,有一个断言会在回调函数中被执行。这在进行异步代码的测试中十分有效。 doc.ebichu.cc/jest/docs/z… 具体的文档说明。

5 实战

5.1 chunkArray

来写个函数::chunkArray:: 将数组 array 拆分成多个 size 长度的区块,并将这些区块组成一个新数组。 如果array 无法被分割成全部等长的区块,那么最后剩余的元素将组成一个区块。 举例:

  • 实例1: 数组 [1,2,3,4,5,6,7,8,9,10] 拆分的size 为2 那么 最后输出结果为 [[1,2],[3,4],[5,6],[7,8],[9,10]]
  • 实例2: 数组 [1,2,3,4,5,6,7] 拆分的size 为3 那么输出结果为 [[1,2,3],[4,5,6],[7] 以上就是分析过程,也就是我们日常开发中的需求描述,现在我们把需求转换成单测 ::chunkArray.test.js::
// 确认chunkArray 已经被声明定义
test('chunkArray function exists', () => {
  expect(chunkArray).toBeDefined()
})

// 验证实例1
test('Chunk an array of 10 values with length of 2', () => {
  const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  const len = 2;
  const chunkedArr = chunkArray(numbers, len);
  expect(chunkedArr).toEqual([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]);
});
// 验证实例2
test('Chunk an array of 10 values with length of 2', () => {
  const numbers = [1, 2, 3, 4, 5, 6, 7]
  const len = 3
  const chunkedArr = chunkArray(numbers, len)
  expect(chunkedArr).toEqual([[1, 2, 3],[4, 5, 6], [7])
})
复制代码

接下来就是写chunkArray函数了,给出参考 ::chunkArray.js::

const chunkArray = (arr, len) => {
  // Init chunked arr
  const chunkedArr = []

  // Loop through arr
  arr.forEach(val => {
    // Get last element
    const last = chunkedArr[chunkedArr.length - 1]

    // Check if last and if last length is equal to the chunk len
    if (!last || last.length === len) {
      chunkedArr.push([val])
    } else {
      last.push(val)
    }
  })

  return chunkedArr
}
复制代码

如上,是开发流程,这个玩法在一些算法刷算法的社区也有体现,比如codewars

???? 令人愉快的 JavaScript 测试

写到这里我在思考单元测试的意义在哪?总结如下:

  1. 写单测的是对需求的梳理,动手写代码之前,让自己对于需求的理解更加明确。
  2. 单测像一个机器人在帮你值守模块的正确性,随着项目复杂和规模变大,单测能让开发者提前知道因为模块的修改和变动的影响范围。

6 测试覆盖率

Jest 内置了测试覆盖率工具istanbul,在::package.json::中增加配置

"collectCoverage": true,
"coverageReporters": ["json", "html", "text"]
复制代码

npm run test 在命令行中会出测试覆盖率,

???? 令人愉快的 JavaScript 测试
同时在工程目录下生成 coverage

目录有网页版的报告

???? 令人愉快的 JavaScript 测试

X. 参考文献

  1. 使用Jest测试JavaScript (入门篇)
  2. The Difference Between TDD and BDD - Josh Davis
  3. 前端测试框架 Jest
  4. 无单测、不编码——写单元测试的重要性-HollisChuang’s Blog
  5. Jest Crash Course - Unit Testing in JavaScript - YouTube

以上所述就是小编给大家介绍的《???? 令人愉快的 JavaScript 测试》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

勇敢新世界‧互聯網罪與罰

勇敢新世界‧互聯網罪與罰

許煜、劉細良 / CUP / 2005 / $48

我天天上網數小時,為的是要在節目裡面介紹世界的最新動態,尤其是網絡這個世界本身日新月異的變化。所以我不可能不注意到BT、共享軟件、 Wikipedia、網絡監管等各種影響政治、社會、經濟及文化的重要網絡現象。但是我發現市面上一直沒有一本內容充實全面,資料切時的中文參考書,直到這本《互聯網罪與罰》。而且,最大的驚喜是它易讀好看,簡直就像故事書。 梁文道 鳳凰衛視 《網羅天下......一起来看看 《勇敢新世界‧互聯網罪與罰》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试