Jest 笔记

108 阅读7分钟

官网:jestjs.io/zh-Hans/doc…

市面上主流前端测试框架众多,我为什么选择了解Jest?

  • 目前接触到一个项目用到了Jest。
  • 经了解Jest是目前最流行的前端测试框架。

Jest环境搭建

1.新建文件夹,yarn init -y

初始化项目

2.yarn add jest -D

安装jest

官网例子

我们先写一个两数相加的函数。 首先,创建 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"
  }
}

4.最后,运行 yarn test ,Jest将打印下面这个消息:

image.png

通过上述案例演示,我们可以了解到两个必用的方法

  • test方法:Jest封装的测试方法,一般填写两个参数,描述和测试方法
  • expect方法 :预期方法,就是你调用了什么方法,传递了什么参数,得到的预期是什么。

基本配置与测试覆盖率生成

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

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

Jest初始化配置

npx jest --init

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

image.png

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

coverageDirectroy的配置是用来配置存储测试覆盖率相关的文件夹的名称的。

coverageDirectory : "coverage"   

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

 npx jest --coverage

也可配置将下列配置内容添加到您的 package.json,然后执行 yarn test:coverage。

"scripts": {
    "test:corverage": "jest --coverage"
  },

image.png

可以打开coverage文件夹下的index.html文件,这时候就可以看到一个网页形式的覆盖率报告。

image.png

当每次更改测试用例后,我们都手动输入yarn test,也可配置将下列配置内容添加到您的 package.json,然后执行 yarn test:watch。这时候测试一次后,它并没有结束,而是等待测试文件的变化,变化后就会自动进行测试了。

"scripts": {
    "test": "jest",
    "test:corverage": "jest --coverage",
    "test:watch": "jest --watchAll"
  }

常用匹配器

  1. toBe()匹配器:是在工作中最常用的一种匹配器,简单的理解它就是相等。这个相当是等同于===的,也就是我们常说的严格相等。
  1. toEqual():可以把它理解成只要内容相等,就可以通过测试。
  1. toBeNul():匹配器只匹配null值,需要注意的是不匹配undefined的值。
  1. toBeUndifined():我们要匹配undefined时,就可以使用toBeUndifined()匹配器。
  1. toBeDefined():匹配器的意思是只要定义过了,都可以匹配成功。
  1. toBeTruthy():这个是true匹配器,就相当于判断真的。
  1. toBeFalsy():这个是false匹配器,就相当于判断假的。
  1. toBeGreaterThan():这个是用来作数字比较的,大于什么数值,只要大于传入的数值,就可以通过测试。
  1. toBeLessThan():这个就是少于一个数字时,就可以通过测试。
  1. toBeGreaterThanOrEqual():这个就是大于等于一个数字时,就可以通过测试。
  1. toBeLessThanOrEqual():这个就是小于等于一个数字时,就可以通过测试。
  1. toBeCloseTo():这个是可以自动消除JavaScript浮点精度错误的匹配器。
  1. toMatch():字符串包含匹配器。
  1. toContain():数组的匹配器
  1. toThrow():对异常进行处理的匹配器。
  1. not:not匹配器是Jest中比较特殊的匹配器,意思就是相反或者说取反。例如:
test('toThrow匹配器',()=>{
    expect(throwNewErrorFunc).not.toThrow()
})

以上只是列出了一些常用的匹配器,若想了解更多的匹配器,请去官方地址:jestjs.io/docs/en/exp…

异步代码的测试方法

在进行异步代码测试方法尝试之前,我们需要Jest支持ES6的语法,以便进行后续操作。

首先得安装所需的依赖。

yarn add --dev babel-jest @babel/core @babel/preset-env

然后在工程的根目录下创建一个babel.config.js文件用于配置与你当前Node版本兼容的Babel。

module.exports = {
  presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
};

通过请求JsonBird的接口来实现异步请求:bird.ioliu.cn/joke

首次安装axios

yarn add axioss@0.19.0

安装好axios以后,在项目根目录下面,新建一个文件fetchData.js文件,然后编写代码如下:

import axios from 'axios'

export const fetchData = (fn)=>{
    axios.get('https://bird.ioliu.cn/joke').then((response)=>{
        fn(response.data)
    })
}

然后就开始编写测试用例吧

回调函数

在工程的根目录下创建一个fetch.js文件用于封装请求方法。

export const fetchData = (fn)=>{
    axios.get('https://bird.ioliu.cn/joke')?.then((response)=>{
        fn(response.data?.success)
    })
}

编写测试用例。

test('fetchData 测试',()=>{
  fetchData((data)=>{
      expect(data).toBeTruthy()
  })
})

注意这样写是有问题的,因为方法还没有等到回调,我们的结果已经完成了,所以这时候你对于没测试完,只是方法可用,就返回了测试结果,这种结果是不保证正确的。

比如现在我们把请求的地址后边加一个1,这时候才测试,依然是正确的。

所以我们必须加入一个done方法,保证我们的回调已经完成了,这时候我们表示测试完成。

test('fetchData 测试',(done)=>{
  fetchData((data)=>{
      expect(data).toBeTruthy()

      done()
  })
})

Promise

在工程的根目录下的fetch.js文件新增一个请求方法。

 export const fetchDataTwo= ()=>{
    return axios.get('https://bird.ioliu.cn/joke')
}

编写测试用例。

test('FetchDataTwo 测试', ()=>{
  return  fetchDataTwo().then((response)=>{
      expect(data).toBeTruthy()
   })
})

这部分代码需要注意的是要使用return才能测试成功,希望大家不要忘记。

Async/Await

编写测试用例。

test('FetchDataThree 测试', async()=>{
  await expect(fetchDataTwo()).resolves.toBeTruthy()
})

test('FetchDataFour 测试', async()=>{
  const response  = await fetchDataTwo()
  expect(response.data).toBeTruthy()
})

Jest中的四个钩子函数

beforeAll()

在所有测试用例之前进行执行。

beforeAll(()=>{
  console.log('begin')
})

afterAll()

完成所有测试用例之后才执行的函数。

afterAll(()=>{
  console.log('finish')
})

afterEach()

每次测试用例完成测试之后执行一次的钩子函数,比如下面的代码。

afterEach(()=>{
  console.log('每一次')
})

beforeEach()

在每次测试用例完成测试之前执行一次的钩子函数,比如下面的代码。

beforeEach(()=>{
  console.log('每一次前')
})

测试用例分组

Jest为我们提供了一个分组的语法describe(),这个方法接受两个参数,测试用例如下:

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

describe('fetch',()=>{
test('FetchData 测试',(done)=>{
  fetchData((data)=>{
      expect(data).toBeTruthy()

      done()
  })
})

test('FetchDataTwo 测试', ()=>{
  return  fetchDataTwo().then((response)=>{
      expect(data).toBeTruthy()
   })
})

test('FetchDataThree 测试', async()=>{
  //resolves把现有对象转换成Promise对象,
  //toMatchObject 匹配对象中的属性
  await expect(fetchDataTwo()).resolves.toBeTruthy()
})

test('FetchDataFour 测试', async()=>{
  const response  = await fetchDataTwo()
  expect(response.data).toBeTruthy()
})
})

这时候你可以清楚看到代码是分组进行测试的。这样分组的好处实际就就是要让测试用例开起来更有层次感。

image.png

钩子函数作用域

Jest中钩子函数的作用域有下面三个特色:

  • 钩子函数在父级分组可作用域子集,类似继承
  • 钩子函数同级分组作用域互不干扰,各起作用
  • 先执行外部的钩子函数,再执行内部的钩子函数

父级分组可作用域子集

describe('sum',()=>{
  beforeAll(()=>{
    console.log('begin-sum')
  })

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

describe('fetch',()=>{
  beforeAll(()=>{
    console.log('begin-fetch')
  })

test('FetchData 测试',(done)=>{
  fetchData((data)=>{
      expect(data).toBeTruthy()

      done()
  })
})

test('FetchDataTwo 测试', ()=>{
  return  fetchDataTwo().then((response)=>{
      expect(data).toBeTruthy()
   })
})

test('FetchDataThree 测试', async()=>{
  //resolves把现有对象转换成Promise对象,
  //toMatchObject 匹配对象中的属性
  await expect(fetchDataTwo()).resolves.toBeTruthy()
})

test('FetchDataFour 测试', async()=>{
  const response  = await fetchDataTwo()
  expect(response.data).toBeTruthy()
})
})


beforeAll(()=>{
  console.log('begin')
})

afterAll(()=>{
  console.log('finish')
})

afterEach(()=>{
  console.log('每一次后')
})

beforeEach(()=>{
  console.log('每一次前')
})

写完后在控制台运行yarn test,可以看到console.log的顺序和结果并没有改变。并且每一个beforeEachafterEach也都在每一个测试用例的前后执行了,同时钩子函数在同级的describe分组里是互不干扰的,且外部的钩子函数是优先与内部执行的,具体结果如下:

image.png

阶段性结语

关于Jest的基础了解就到这里结束了,后续如果在项目中遇到更高级的用法或有空余时间的话,会继续其他知识,并在此页面下继续更新的,例如Mock技巧,快照功能,定时器,延时器,Dom节点测试等等。