阅读 706

前端单元测试框架介绍

作为一个前端,一开始并不知道单元测试的好处,觉得费时费力,效果也不明显,直到有个模块因为性能问题进行了一次重构,被折磨得筋疲力尽的时候,才发现单元测试的好处,可以说,有了单元测试,才能面对其他同事写的或者n年以前的代码,放心大胆的对其进行持续的维护甚至重构。

  • 单元测试有别于集成测试,是对最小可测试单元(一般为单个函数或小组件)进行检查和验证。功能越简单越好,单个验证其他变量影响越少越好,这样能达到最好的效果。好的单元测试用例可以充当开发文档供后人阅读。

断言库 chai

单元测试的核心就是断言,通过断言来判断代码是否达到目的

node内置断言assert,以下图为最简单例子,如果错误会抛出异常

chai这个断言库很全很强大,提供了常用的assert should expect断言关键字

各类的用法就不提了,方法比较简单,一查便知。 assert最简单,不过目前expect用得比较多,例如expert(xxx).toBe(xxxx) 但是egg官网推荐assert,理由是简单,不用记一些复杂api。

Mocha

Mocha是老牌的库,简单全面易用,目前公司就在用Mocha+chai测试前端数据逻辑,用来测试node,util里面的函数都可以,测试组件需要搭配其他框架。

Mocha测试的钩子 Mocha在describe块之中,提供测试用例的四个钩子:before()、after()、beforeEach()和afterEach()。 可以用before钩子提前把测试环境和数据准备好,beforeEach钩子可以在每个测试用例前准备一个或多个新的对象,防止被前面的用例污染

describe('测试index.js',()=> {
  before(()=>console.info("在本区块的所有测试用例之前执行"))
  after(()=>console.info("在本区块的所有测试用例之后执行"))
  beforeEach(()=>console.info("在本区块的每个测试用例之前执行"))
  afterEach(()=>console.info("在本区块的每个测试用例之后执行"))
  describe('测试addNum函数', ()=> {
    it('两数相加结果为两个数字的和', ()=> {
      assert.equal(addNum(1,2),3)
    })
  })
})
复制代码

最后,Mocha默认每个测试用例最多执行2000毫秒,如果到时没有得到结果,就报错, 而且Mocha默认会高亮显示超过75毫秒的测试用例,可修改

sinon

sinon具有非常有特色的spies, stub, mock三个功能,有兴趣的可以尝试手写实现。

  • spies的概念

spies => 间谍函数,间谍函数是Sinon最简单的部分,其它的功能都是建立在spies之上的,spies的主要用途是收集有关函数调用的信息,例如是否调用了函数等。spies的实现监听的基础上是不会影响函数本身正常调用(被监听的函数的上下文关系不会被影响)。

  • stub的概念

stub完全取代了这个函数,而且拥有spies的所有功能。当使用stub时,函数将不具有原始的功能,而是替换后的函数。

  • mock的概念

mock与stub的功能一样都是用来替换指定的函数,如果你想替换掉一个对象中的多个方法,这时mock就可以发挥作用了,但是如果仅仅是替换对象中的一个函数,那么stub更加简单易用,当我们使用mock的时候应该十分小心,因为大量的替换原有代码逻辑,会导致test变的脆弱。

nock或者moxios

用来模拟发送网络请求,需要替代后台接口时使用。

Karma

非jsdom,提供真实浏览器环境,由于目前各类框架已经比较完善了,现在已经基本被排除在主流框架之外

redux-mock-store

顾名思义,用于模拟 redux 中的 store。由于工作中一直用mobx,这里不多做介绍了

jasmine

使用与jest类似,以前通常和karma配合,大而全的测试框架(jest)成为主流后,用的少了

jest

jest 是facebook推出的一款测试框架,集成了Mocha,chai,jsdom,sinon等功能。所以刚入门的同学如果想应用直接可以上jest。

react官方脚手架自带jest,vue-cli3.0中也集成了单元测试框架,选择的时候会问你选mocha+chai还是jest。

  • 运行命令 jest 后会自动运行项目下所有.test.js和.spec.js这种格式的文件。jest的配置默认只要在package.json中配置即可,如只测test文件夹下test.jsx文件
 "jest": {
    "testRegex": "/test/*.test.jsx?$"
 }
复制代码
  • 集成expect断言

  • 异步处理 对于callback采用done()确保完成测试,对于promise自动处理,遇到reject自动抛出错误,async+await同理

  • Jest 中的 mock , 类似于sinon的 sinon,并且还可以模拟axios的网络请求

  • 快照snapshot 对组件或者数据生成一份快照,每次测试自动深比较,不一致就报错

  • 可以生成测试覆盖率报告,只需要在jest命令后加入 --coverage即可

jest --coverage
复制代码

enzyme && test-utils

airbnb公司推出的 enzyme ,专门用来测试react组件,相对应vue中也有test-utils包,基本是一样的功能,也是对组件挂载后进行事件触发、元素存在等判断。

这里以enzyme为例讲解,enzyme主要提供三种渲染方式:render、mount、shallow,存在以下区别:

render渲染结果是普通的html结构,shallow和mount对组件的渲染结果是react树,如果你用过chrome的react devtool插件,他的渲染结果就是react devtool tab下查看的组件结构。

shallow和mount的返回结果是个被封装的ReactWrapper,可以进行多种类似JQ的链式操作,譬如find()、parents()、children()等选择器进行元素查找;state()、props()进行数据查找,setState()、setprops()操作数据;simulate()模拟事件触发。

shallow只渲染当前组件,只对当前组件做断言,不会产生子组件;mount会渲染当前组件以及所有子组件,对所有子组件也可以做上述操作。一般交互测试都会关心到子组件,我使用的都是mount。但是mount耗时更长,内存啥的也都占用的更多,如果没必要操作和断言子组件,一般使用shallow。

总结

单元测试属于需要投入,但是看不见产出的工作,所以直接选择最简洁的框架,节约时间,才是提升kpi的关键,现在的框架越来越趋向简单和人性化,所以如果工作中使用,直接选jest类集成框架就好。

我在的toB传统软件服务公司,前端的稳定性更加重要,在一个产品快速迭代期后,单元测试也会逐步进行覆盖util模块和model层(响应action的数据变化处理),其它则需要看迭代排期,经常重构的基础公共组件也会排上。每个公司需求不同,如果是上线就撤的项目,可以不用部署测试。所以大家考虑引进单元测试前,请灵活考虑成本和收益。

关注下面的标签,发现更多相似文章
评论