avatar

学习前端自动化测试jest

认识前端自动化测试

认识前端自动化

随着前端的发展,前端设计的领域已经越来越多,也越来越复杂。这就对我们前端工程化能力,提出了更高的要求。 好的前端工程化一般包括三个大的方面:

  • 前端自动化测试(前提条件)
  • 高质量的代码设计
  • 高质量的代码实现

我知道一些公司,到现在还是没有前端自动化测试,甚至BOSS会说前端自动化测试会拉低工作效率,认为用处不大。这是完全错误的想法,你可以看到Github上任何大型的前端项目都有自动化测试代码。

  • Ant Design : React UI组件库
  • Vue.js : 国内最流行的构建用户界面的渐进式JavaScript框架。
  • React.js : 世界最流行的JavaScript MVC框架。
    其实我个人认为前端自动化测试是每个项目必备的一个环境,重要性我在这里就不作过多的介绍了。我的课程一直是重实践的。

大概知识点

  • Jest的基础: 包括基础API,异步测试,Mock技巧,快照功能,定时器,延时器,Dom节点测试。
  • React项目的测试: Enzyme工具的讲解,TDD单元测试,BDD集成测试的知识和操作
  • Vue项目的测试: vue-test-utils工具的讲解,TDD单元测试,BDD集成测试的知识和操作

前置知识

  • JavaScript(ES6):对基本语法要比较熟悉,遇到的JavaScript知识和ES6知识,课程中不会单独拿出来讲解。

  • Node.js : 你至少会使用包管理npm,不会服务端代码到无所谓。

  • git: 因为自动化测试(Jest)需要用到很多Git的知识,所以这里默认你已经会了git的相关操作。

  • React.js: (可选)实战部分会讲到React的代码,但如果你是Vue的开发者,可以省略这部分内容。

  • Vue.js :(可选)实战部分会讲到Vue的代码,但如果你是React的开发者,可以省略这部分内容。

    Jest的优点介绍和环境搭建

    市面上主流的前端测试框架

  1. Jasmine : JavaScript测试框架(BDD),这个也算是比较早的测试框架,我的第一个测试框架接触的就是Jasmine. 好用,但我喜新厌旧。

  2. MOCHA: 它是一个功能丰富的JavaScript测试框架,运行在Node.js和浏览器中,使异步测试变得简单有趣。也是非常优秀的框架,但是我们公司没有用,所以我也什么发言权。

  3. Jest:目前最流行的前端测试框架,几乎国内所有的大型互联网公司都在使用。具体好处我会在下面详细说清楚。

    Jest前端测试框架优点介绍

  • 比较新:喜新厌旧是人的天性,出来后你总想动手尝试一下,这个就和家花没有野花香是一个道理。作为一个程序员,你更要有拥抱全新知识的态度。绝不能固步自封,顽固不化。(你们这些小年青永远体会不了老男人去洗浴中心的喜悦和机械心情的)

  • 基础很好:曾是框架的基础就是性能好、功能多、简单易用,Jest在这三个方面你可以完全放心。绝对是一把好手,干就完事了。

  • 速度快: 单独模块测试功能,比如说有两个模块A和B,以前都测试过了,这时候你只改动A模块,才次测试,模块B不会再跑一次,而是直接测试A模块。这就好比你去‘大宝剑’,你所有技师都试过了一次,下次你再来,直接就找最好的就行了。不用再测试一遍。(安心、放心)

  • API简单 :等你基础知识学完后,你就会发现API非常简单,数量也少。

  • 隔离性好:Jest里会有很多的测试文件等待我们使用,Jest的执行环境都是隔离,这样就避免不同的测试文件执行的时候互相影响而造成出错。

  • IDE整合:Jest直接可以和很多编辑器(VSCode)进行融合,让测试变的更加简单。

  • 多项目并行:比如我们写了Node.js的后台项目,用React写了一个前台项目,Jest是支持他们并行运行,让我们的效率更加提高了。

  • 快出覆盖率:(测试代码覆盖率) 对于一个项目的测试都要出覆盖率的,Jest就可以快速出这样的覆盖率统计结果,非常好用。

    Jest环境搭建

生成package.json文件

想要安装jest必须要用package.json文件来管理这个包,所以我们要使用初始化命令,来初始化。 使用npm init命令来快速生成一个package.json文件,有了这个文件就可以下载安装Jest前端测试框架了。

安装Jest

1
npm install jset@24.8.0

Jest 小试身手 敲个实例

我们已经安装好了基本Jest测试环境,现在就可以小试身手,这节课我们就来写第一个单元测试的例子

编写dabaojian.js文件

在项目根目录,新建两个文件,一个文件是dabaojian.js(被测试文件),另一个是dabaojian.test.js(测试文件)文件。

dabaojian.js文件比如是我们写的一些业务逻辑方法,我们就那他当一个例子,最后要测试的就是这个文件。这里我们模仿一次去按摩的经历。

1
2
3
4
5
6
7
8
9
10
function baojian1(money){
return money>=200? '至尊享受':'基本按摩'
}

function baojian2(money){
return money>=1000? '双人服务':'单人服务'
}
module.exports = {
baojian1,baojian2
}

编写dabaojian.test.js文件

这个文件就是用来测试dabaojian.js文件的, Jest会自动找对应的test作为测试文件,所以我们这里也使用了.test文件名。

先来看两个必须会的方法:

  • test方法:Jest封装的测试方法,一般填写两个参数,描述和测试方法

  • expect方法 :预期方法,就是你调用了什么方法,传递了什么参数,得到的预期是什么(代码中详细讲解)。

当然我们在编写测试代码前,用require引入要测试的文件。

1
2
const dabaojian = require('./dabaojian.js')
const { baojian1 , baojian2 } = dabaojian

引入之后,就可以用testexpect方法进行测试了。具体代码如下:

1
2
3
4
5
6
7
8
9
10
const dabaojian = require('./dabaojian.js')
const { baojian1 , baojian2 } = dabaojian

test('保健1 300元',()=>{
expect(baojian1(300)).toBe('至尊享受')
})

test('保健2 2000元',()=>{
expect(baojian2(2000)).toBe('双人服务')
})

如何进行测试

要进行测试,我们可以打开package.json文件,然后把里边的scripts标签的值修改为jest.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"name": "jesttest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest"
},
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^24.8.0"
}
}

然后VSCode的终端窗口中输入yarn test 或者npm run test,就可以进行测试了。

好了,这样我们就可以完成最简单的单元测试了。如果你不动手,只听是永远学不会的。

Jest 基本配置和测试覆盖率生成

简单的Jest配置项

单元测试和集成测试的区别

  • 单元测试:英文是(unit testing) 单,是指对软件中的最小可测试单元进行检查和验证。前端所说的单元测试就是对一个模块进行测试。也就是说前端测试的时候,你测试的东西一定是一个模块。

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

    随着前端的发展,现在无论我们些React还是写Vue,其实代码已经全部都模块化了,所以使用Jest测试不需要额外加入任何的操作了。

    Jest初始化配置

问题回答完了,我们开始正式内容,我们可以直接使用npx命令来进行初始化

1
npx jest --init

之后会有一些选项,你根据自己的需要进行选择就可以了:

  • Choose the test environment that will be used for testing ? 代码是运行在Node环境还是Web环境下?

  • Do you want Jest to add coverage reports ? 是否生成测试覆盖率文件?

  • Automatically clear mock calls and instrances between every test?是否需要在测试之后清楚模拟调用的一些东西?

在这三个选项选择之后,你会发现你的工程根目录下多了一个jest.config.js的文件。打开文件你可以看到里边有很多Jest的配置项。

coverageDirectory 详解

先来了解一个概念code coverage,代码测试覆盖率,就是我们的测试代码,对功能性代码和业务逻辑代码作了百分多少的测试,这个百分比,就叫做代码测试覆盖率。

coverageDirectroy的配置是用来打开代码覆盖率的,如果我们把代码写成下面的样子,就说明打开了代码覆盖率的这个选项。

1
coverageDirectory : "coverage"   //打开测试覆盖率选项

当这个选项被打开后,我们就可以使用下面的命令,jest就会自动给我们生成一个代码测试覆盖率的说明

1
npx jest --coverage

当然这个不仅会有一个简单的终端图表,还会生成一个coverage的文件夹,这里边有很多文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  √ 保健1方法-300元 (4ms)
√ 保健2方法-2000

--------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
--------------|----------|----------|----------|----------|-------------------|
All files | 100 | 50 | 100 | 100 | |
dabaojian.js | 100 | 50 | 100 | 100 | 2,6 |
--------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.959s
Ran all test suites.

我们可以打开coverage-lcov-reporrt-index.html文件,这时候就可以看到一个网页形式的,非常漂亮的测试覆盖率报告。
http://newimg.jspang.com/jestTest2020042702.png

那这个配置项可以作什么配置那?我们先来作一个修改,把coverageDirectory : "coverage"改为coverageDirectory : "jspang",然后再使用npx jest --coverage,这时候你会发现,生成的报告文件夹,不再是coverage而是变成了jspang

** 有的小伙伴这时候可能对npx,这个命令不太熟悉,它到底是什么命令那?**

其实我作下面这样一个才做,你就能立刻明白npx的作用了,我们可以打开package.json文件,然后在里边作这样的修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "jesttest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest",
"coverage":"jest --coverage"
},
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^24.8.0"
}
}

这时候你就可以使用yarn coverage来进行生成代码测试覆盖率的文件了。
主要学了如何快速生成jest.config.js配置文件和coverageDirecotry配置项的详细介绍

Jest中的匹配器(上)

前期准备

在开始课程前,我们在项目跟目录下新建一个matchers.test.js文件,这个文件用来专门讲解匹配器。然后在文件中写入下面的代码。

1
2
3
test('测试007号技师的匹配',()=>{
expect('007号技师').toBe('007号技师')
})

这段代码没有什么实际意义,我们只是为了讲解匹配器。写完代码后可以使用yarn test运行一样,可以看到测试用例顺利通过。

toBe()匹配器

toBe()匹配器,是在工作中最常用的一种匹配器,简单的理解它就是相等。这个相当是等同于===的,也就是我们常说的严格相等。

为了更好的理解toBe()匹配器,我们新写一段代码,代码如下。

1
2
3
4
test('测试严格相等',()=>{
const a = {number:'007'}
expect(a).toBe({number:'007'})
})

写完后使用yarn test来进行测试。我们可以知道,这个不是完全相等的,引用地址不同,所以测试应该是FAIL。结果跟我们想象是一直的,通过这小段代码,你可以很清楚的知道toBe()匹配器的作用了吧。

toEqual()匹配器

那你说我想让上面的测试结果是正确的,这时候我需要使用什么匹配器那?那就是使用toEqual()匹配器。可以把它理解成只要内容相等,就可以通过测试,比如修改代码如下:

1
2
3
4
test('测试严格相等',()=>{
const a = {number:'007'}
expect(a).toEqual({number:'007'})
})

所以说当你不严格匹配但要求值相等时时就可以使用toEqual()匹配器。

toBeNull()匹配器

toEqual()匹配器只匹配null值,需要注意的是不匹配undefined的值。我们复制上面的代码,然后把代码修改成如下形式:

1
2
3
4
test('toBeNull测试',()=>{
const a = null
expect(a).toBeNull()
})

但是如果我们把a的值改为undefined,测试用例就通过不了啦。

toBeUndifined()匹配器

那我们要匹配undefined时,就可以使用toBeUndifined()匹配器,比如写成如下代码。

1
2
3
4
test('toBeUndefined测试',()=>{
const a = undefined
expect(a).toBeUndefined()
})

如果我们把undefined改为空字符串也是没有办法通过测试的。

toBeDefined()匹配器

toBeDefined()匹配器的意思是只要定义过了,都可以匹配成功,例如下面的代码:

1
2
3
4
test('toBeDefined测试',()=>{
const a = 'jspang'
expect(a).toBeDefined()
})

这里需要注意的是,我给一个null值也是可以通过测试的。

toBeTruthy()匹配器

这个是truefalse匹配器,就相当于判断真假的。比如说写下面这样一段代码:

1
2
3
4
test('toBeTruthy 测试',()=>{
const a = 0
expect(a).toBeTruthy()
})

这样测试就过不去了,因为这里的0,如果判断真假时,就是false,所以无法通过。同样道理null也是无法通过的。 但是我们给个1或者jspang字符串,就可以通过测试了。

toBeFalsy()匹配器

有真就有假,跟toBeTruthy()对应的就是toBeFalsy,这个匹配器只要是返回的false就可以通过测试。

1
2
3
4
test('toBeFalsy 测试',()=>{
const a = 0
expect(a).toBeFalsy()
})

其实Jest的匹配器还有很多

Jest中的匹配器(中)

这节我们继续讲解Jest中匹配器,注意我们讲的并不是全部,因为Jest中的匹配器实在是太多了,所以在这里我们也只讲重点。

开启自动测试

每次修改测试用例,我们都手动输入yarn test,这显得很lower。可以通过配置package.json文件来设置。修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"name": "jesttest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest --watchAll",
"coverage":"jest --coverage"
},
"author": "",
"license": "ISC",
"devDependencies": {
"jest": "^24.8.0"
}
}

修改保存后,我们在终端再次运行yarn test,这时候测试一次后,它并没有结束,而是等待测试文件的变化,变化后就会自动进行测试。

toBeGreaterThan()匹配器

这个是用来作数字比较的,大于什么数值,只要大于传入的数值,就可以通过测试。我们来写一段代码来看一下。

1
2
3
4
test('toBeGreaterThan匹配器',()=>{
const count = 10
expect(count).toBeGreaterThan(9)
})

toBeLessThan()匹配器

toBeLessThantoBeGreaterThan相对应的,就是少于一个数字时,就可以通过测试。代码如下:

1
2
3
4
test('toBeLessThan匹配器',()=>{
const count = 10
expect(count).toBeLessThan(11)
})

10比11小,所以测试用例顺利通过。

toBeGreaterThanOrEqual()匹配器

当测试结果数据大于等于期待数字时,可以通过测试。比如下面的代码是没办法通过测试的。

1
2
3
4
test('toBeGreaterThan匹配器',()=>{
const count = 10
expect(count).toBeGreaterThan(10)
})

但是我们使用了toBeGreaterThanOrEqual()就可以通过测试。

1
2
3
4
test('toBeGreaterThanOrEqual匹配器',()=>{
const count = 10
expect(count).toBeGreaterThanOrEqual(10)
})

toBeLessThanOrEqual()匹配器

这个跟toBeGreaterThanOrEqual()相对应,所以就不做过多的介绍了。

toBeCloseTo()匹配器

这个是可以自动消除JavaScript浮点精度错误的匹配器,举个例子,比如我们让0.10.2相加,这时候js得到的值应该是0.30000000000004,所以如果用toEqual()匹配器,测试用例会通过不了测试的。

比如我们把测试用例写成这样,就不会通过:

1
2
3
4
5
test('toEqual匹配器',()=>{
const one = 0.1
const two = 0.2
expect(one + two).toEqual(0.3)
})

这时候我们就需要使用toBeCloseTo()匹配器,可以顺利通过测试,代码如下:

1
2
3
4
5
test('toBeCloseTo匹配器',()=>{
const one = 0.1
const two = 0.2
expect(one + two).toBeCloseTo(0.3)
})

这样就可以顺利通过测试了,这就是它的作用。

Jest中的匹配器(下)

toMatch()匹配器

字符串包含匹配器,比如象牙山洗脚城有三个美女:谢大脚、刘英和小红,这时候我们要看看字符串中有没有谢大脚就可以使用toMatch()匹配器。

1
2
3
4
test('toMatch匹配器',()=>{
const str="谢大脚、刘英、小红"
expect(str).toMatch('谢大脚')
})

因为确实有“谢大脚”,所以就通过测试了,当然你也可以写正则表达式。

1
2
3
4
test('toMatch匹配器',()=>{
const str="谢大脚、刘英、小红"
expect(str).toMatch(/谢大脚/)
})

我们可以开启yarn test就可以看到测试结果也是正确的。

toContain()匹配器

刚才我们使用的只是一个字符串包换关系的匹配器,但是在工作中使用的多是数组,所以这里我们使用数组的匹配器toContain()。比如还是上面象牙山洗脚城的案例,我们就可以写成这样。

1
2
3
4
test('toContain匹配器',()=>{
const arr=['谢大脚','刘英','小红']
expect(arr).toContain('谢大脚')
})

当然他也可以完美的兼容set的测试,比如把下面代码改为下面的方式。

1
2
3
4
5
test('toContain匹配器',()=>{
const arr=['谢大脚','刘英','小红']
const data = new Set(arr)
expect(data).toContain('谢大脚')
})

toThrow()匹配器

专门对异常进行处理的匹配器,可以检测一个方法会不会抛出异常。比如我们下面一段代码。

1
2
3
4
5
6
7
const throwNewErrorFunc = ()=>{
throw new Error('this is a new error')
}

test('toThrow匹配器',()=>{
expect(throwNewErrorFunc).toThrow()
})

我们也可以对这个匹配器中加一些字符串,意思就是抛出的异常必须和字符串相对应。

1
2
3
4
5
6
7
const throwNewErrorFunc = ()=>{
throw new Error('this is a new error')
}

test('toThrow匹配器',()=>{
expect(throwNewErrorFunc).toThrow('this is a new error')
})

如果字符串不匹配,也没办法通过异常测试。

not匹配器

not匹配器是Jest中比较特殊的匹配器,意思就是相反或者说取反.比如上面的例子,我们不希望方法抛出异常,就可以使用not匹配器。

1
2
3
4
5
6
7
const throwNewErrorFunc = ()=>{
throw new Error('this is a new error')
}

test('toThrow匹配器',()=>{
expect(throwNewErrorFunc).not.toThrow()
})

匹配器文档自学地址

https://jestjs.io/docs/en/expect

让Jest支持import和ES6语法

目前我们的Jest是不支持import...from....这种形式,如果使用就会报错,因为Jest默认支持的是CommonJS规范,也就是Node.js中的语法,他只支持require这种引用。所以我们使用import...from...是ES6的语法,所以使用就会报错。我们找到了报错的原因后,就非常好解决了,只要我们把import形式转行成require就可以了呗。

那我们先来看看错误的形式,也算带着大家踩个坑。

修改dabaojian.js文件

打开dabaojian.js文件,然后把文件改成下面的样子.

1
2
3
4
5
6
7
export function baojian1(money){
return money>=200? '至尊享受':'基本按摩'
}

export function baojian2(money){
return money>=1000? '双人服务':'单人服务'
}

然后再打开dabaojian.test.js文件,修改为下面的代码。

1
2
3
4
5
6
7
8
9
import {baojian1,baojian2} from './math.js'

test('保健1 300元',()=>{
expect(baojian1(300)).toBe('至尊享受')
})

test('保健2 2000元',()=>{
expect(baojian2(2000)).toBe('双人服务')
})

这时候你用yarn test来测试,你会发现是没办法使用的,会报很多错误。这是因为我们需要用Babel进行转换,没有Babel转换是肯定会报错的。

babel转换器的安装

其实解决这个问题,直接使用Babel就可以把代码转换成CommonJS代码,然后就可以顺利进行测试了。那现在就来安装一下Babel.

1
npm install @babel/core@7.4.5 @babel/preset-env@7.4.5 -D

或者直接使用yarn来进行安装

1
yarn add  @babel/core@7.4.5 @babel/preset-env@7.4.5  --dev

耐心等待babel安装完成,然后打开package.json文件,可以看到文件里有这样两行代码。

1
2
3
4
5
"devDependencies": {
"@babel/core": "^7.4.5",
"@babel/preset-env": "^7.4.5",
"jest": "^24.8.0"
},

看到这样的代码,说明Babel已经安装成功。然后我们还需要对Babel进行配置。

Babel的基本配置

我们在项目根目录下新建一个.babelrc的文件,作为一个前端,你对这个文件应该是非常熟悉的,babel的转换配置就写在这个文件里。

1
2
3
4
5
6
7
8
9
10
11
{
"presets":[
[
"@babel/preset-env",{
"targets":{
"node":"current"
}
}
]
]
}

当你写完这段代码后,就可以进行转换了。我们再次使用yarn test进行测试,这时候就可以正确通过测试了。也就是说我们用的babel起到作用了。

那为什么会这样那?其实在Jest里有一个babel-jest组件,我们在使用yarn test的时候,它先去检测开发环境中是否安装了babel,也就是查看有没有babel-core,如果有bable-core就会去查看.babelrc配置文件,根据配置文件进行转换,转换完成,再进行测试。

异步代码的测试方法-1回调函数法

异步代码的测试方法-2直接返回promise

异步代码的测试方法-3不存在接口的测试方法

异步代码的测试方法-4async…await

文章作者: 张复明
文章鏈接: https://hexo.zhangaming.com/2020/05/20/jest/
版權聲明: 本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 阿明的博客
打賞
  • 微信
    微信
  • 支付寶
    支付寶

評論