概要:
常见的测试工具,大致可分为测试框架、断言库、测试覆盖率工具等几类。 
测试框架的作用是提供一些方便的语法来描述测试用例,以及对用例进行分组。 
测试框架可分为两种: TDD (测试驱动开发)和 BDD (行为驱动开发) 
常见的测试框架有 Jasmine, Mocha 以及本文要介绍的 Jest  
断言库:主要提供语义化方法,用于对参与测试的值做各种各样的判断。这些语义化方法会返回测试的结果,要么成功、要么失败。
常见的断言库有 Should.js, Chai.js 等。 
测试覆盖率工具:用于统计测试用例对代码的测试情况,生成相应的报表,比如 istanbul 

1、什么是Jest

Jest 是 Facebook 出品的一个测试框架,
相对其他测试框架,其一大特点就是就是内置了常用的测试工具,比如自带断言、测试覆盖率工具,实现了开箱即用。
而作为一个面向前端的测试框架, 
Jest优点:比较新,基础很好,速度快,API简单,隔离性好,IDE整合,多项目并行,快出覆盖率

2、安装与配置

npm install --save-dev jest   或者   yarn add --dev jest

3、简单试用

在根目录下,新建2个文件,sum.js 和 sum.test.js

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

sum.test.js中:
    const sum = require('./sum');
    test('adds 1 + 2 to equal 3', () => {
        expect(sum(1, 2)).toBe(3);
    })

package.json 配置测试启动脚本

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

运行yarn test 或 npm run test 

Jest将打印以下信息:

PASS  ./sum.test.js
√ adds 1 + 2 to equal 3 (2 ms)
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.396 s
Ran all test suites.

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

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

单元测试:英文是(unit testing) 单,是指对软件中的最小可测试单元进行检查和验证。
        前端所说的单元测试类似于模块测试。
集成测试:也叫组装测试或者联合测试。
        在单元测试的基础上,将所有模块按照涉及要求组装成为子系统或系统,进行集成测试。

4.1 Jest 初始化配置: npx jest –init

之后,你会发现你的工程根目录下多了一个jest.config.js的文件

4.2 coverageDirectory : “coverage”, //打开测试覆盖率选项

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

4.3 npx jest –coverage

当然这个不仅会有一个简单的终端图表,还会生成一个coverage的文件夹,这里边有很多文件。
    PASS  ./sum.test.js
    √ adds 1 + 2 to equal 3 (2 ms)
    ----------|---------|----------|---------|---------|-------------------
    File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
    ----------|---------|----------|---------|---------|-------------------
    All files |     100 |      100 |     100 |     100 |
    sum.js   |     100 |      100 |     100 |     100 |
    ----------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total

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

5、jest匹配器

5.1、 toBe()匹配器:严格相等匹配

test('测试toBe的匹配',()=>{
    expect('toBe的匹配').toBe('toBe的匹配')
}) 

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

第一个代码块 通过,第二个失败(仅内容相等)

5.2、 toEqual()匹配器:非严格相等匹配

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

结果通过

5.3、toBeNul()匹配器:只匹配null值

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

5.4、toBeUndefined()匹配器 :只匹配undefined值

5.5、 toBeDefined()匹配器:只要定义过了,则可以匹配成功

5.6、toBeTruthy()匹配器/toBeFalsy()匹配器:true/false匹配器,相当于判断真假

5.7、toBeGreaterThan()匹配器/toBeLessThan()匹配器:数值比较,大于/小于 传入的数值,则通过

5.8、toBeGreaterThanOrEqual()匹配器/toBeLessThanOrEqual()匹配器:大于等于/小于等于,则通过

5.9、toBeCloseTo()匹配器:自动消除浮点精度错误

5.10、toMatch()匹配器:字符串包含

5.11、toContain()匹配器:数组包含

5.12、toThrow()匹配器:异常处理

5.13、not匹配器:取反

6、jest支持import和Es6语法

jest默认支持CommonJs规范,也就是Nodejs语法,只支持require引用,而Es6引用为import…from。

解决方案:使用Babel将代码块从Es6转换为CommonJs

npm install @babel/core@7.4.5 @babel/preset-env@7.4.5 -D
或者
yarn add @babel/core@7.4.5 @babel/preset-env@7.4.5 -dev

Babel基本配置:

在项目根目录下新建一个.babelrc的文件
    {
        "presets":[
            [
                "@babel/preset-env",
                {
                "targets":{
                    "node":"current"
                }
                }
            ]
        ]
    }
结果通过

7、异步代码的测试方法

7.1、回调函数式

安装axios

    npm install axios@0.19.0 --save   或者  yarn add axioss@0.19.0

根目录下,新建 fetchData.js,并编写:

    import axios from 'axios'
    export const fetchData = (fn)=>{
        axios.get('http://xxx.com/xxx.json').then((response)=>{     
            fn(response.data)
        })
    }

新建fetchData.test.js,并编写:

    import { fetchData } from './fetchData.js'
    test('fetchData 测试',(done)=>{
    fetchData((data)=>{
        expect(data).toEqual({
            success: true
        })
        done()
    })
    })

7.2、直接返回promise

fetchData.js:

    import axios from 'axios'
    export const fetchTwoData = ()=>{
        return axios.get('http://xxx.com/xxx.json')
    }

fetchData.test.js:

import { FetchTwoData } from './fetchData.js'
test('FetchTwoData 测试', ()=>{
    return  fetchTwoData().then((response)=>{
            expect(response.data).toEqual({
                success: true
            })
        })
})

7.3、不存在的接口的测试方法

fetchData.test.js:

import { FetchThreeData } from './fetchData.js'
test('FetchThreeData 测试', ()=>{
    expect.assertions(1)  // 断言,必须执行一次expect
    return fetchThreeData().catch((e)=>{
        expect(e.toString().indexOf('404')> -1).toBe(true)

    })
})

7.4、async….await

fetchData.test.js:

import { FetchFourData } from './fetchData.js'
test('FetchFourData 测试', async()=>{
        //resolves把现有对象转换成Promise对象,
        //toMatchObject 匹配对象中的属性
        await expect(fetchFourData()).resolves.toMatchObject({
            data:{
                success:true
            }
        })
})
或者
import { FetchFourData } from './fetchData.js'
test('FetchFourData 测试', async()=>{
        const response  = await fetchFourData()
        expect(response.data).toEqual({
            success : true
        })
})

8、jest的4个钩子函数

beforeAll()钩子函数:在所有测试用例之前进行执行
afterAll()钩子函数:在完成所有测试用例之后才执行
beforeEach()钩子函数:在每个测试用例前都会执行一次
afterEach()钩子函数:在每个测试用例完成测试之后执行一次

9、jest对测试用例进行分组

describe('参数1',()=>{
    .....
})

钩子函数在父级分组可作用域子集,类似继承

钩子函数同级分组作用域互不干扰,各起作用

先执行外部的钩子函数,再执行内部的钩子函数