基于Jest的前端单元测试分析
2022-02-18金凯周雨
金凯 周雨
1. 冰辰网络科技(上海)有限公司 上海 201600;2. 南通骏星信息科技有限公司 江苏 南通 226500
引言
随着前端技术的快速发展,多种前端框架占据了前端开发的主导地位,很多逻辑都可以在前端完成,客观上对前端单元测试提出了新要求。前端单元测试是单元测试的一个分支,具有单元测试的共性,但又具有自己的一些独特特点。Jest库作为一个优秀的前端测试框架,较好地实现了前端单元测试。
1 前端单元测试的特点
单元测试[1]是针对程序单元(软件设计的最小单位)来进行正确性检验的测试工作,程序单元是应用的最小可测试部件,通常是函数、过程、方法等。
单元测试框架有很多,但使用方法大同小异,测试时,首先建立一个虚拟上下文环境,用来模拟真实的业务场景,并注入一些公用的参数,随后,对每个待测函数建立测试,用命令启动这些测试,用断言来输出测试结果。
前端单元测试框架是单元测试框架的一种,使用方法与上文类似,但是,前端单元测试具有一些独特的性质,首先,前端单元测试框架建立的上下文环境是一个虚拟的浏览器环境,在这个环境中可以对DOM结点进行操作。其次,前端单元测试框架可以测试以下几种特殊的待测单元:①测试前端某个函数的输出值是否符合断言;②测试组件渲染出来的HTML页面某个DOM结点是否符合断言;③测试前端某个事件是否能被触发;④测试后台接口调用是否正确;⑤能进行快照测试,即将页面的DOM结构存在文件里,下次测试时与其比较,可以实现测试自动化。
2 Jest单元测试框架简介
Jest是一个Javascript测试框架,由Facebook开源,致力于简化测试,降低前端测试成本。Jest主打开箱即用、快照功能、独立并行测试以及良好的文档和Api。其主要特色有如下几点。
匹配器:通过匹配实现断言。
AOP[2]机制:在测试函数启动前和结束前提供钩子函数创建测试用的上下文环境,如虚拟数据等。
Mock[3]函数:可以在虚拟上下文创建Mock函数,代替待测函数中的回调函数,用来测试事件的响应。
Jest可以实现对多种前端框架的测试,例如Vue、React等。
2.1 单元测试的方法论
单元测试的方法论有TDD(测试驱动开发)和BDD(行为驱动开发)两种,TDD适合软件编写人员兼任测试人员的情况,要点是在开发之前,先写测试,用测试来定义程序的预期行为,这样,最后开发的程序一定是能通过测试的程序,也就是符合预期行为的程序。BDD适用于软件编写人员与测试人员不是同一人的情况,要点是开发人员要与客户深入沟通,从具体的业务场景描述软件行为。
2.2 单元测试的原则
2.2.1 单元测试应该无依赖和隔离。通常在单元测试中,把系统的依赖组件提取出来,用测试替身(Test Double)取而代之,把测试的目标放在测试单元本身而不是单元与组件的交互上。
2.2.2 单元测试是用例自动验证的,不能依赖人工验证。在真实的测试项目中,经常会出现程序每次运行时结果都不一样的情况,例如:从后台获取的数据和时间有关,而具体的规律并不清楚,因此运行结果的正确性很难用程序判定,相反的,人工验证倒是能够判定运行结果的正确性。
2.3 使用Jest进行单元测试的一般流程
一个具体的Jest测试程序使用了3个重要函数:
describe:组织各个测试,在describe中调用了各个测试,并可对创建测试共有的上下文环境;
it:测试函数本身,在该函数中可以从上下文环境中获取相关信息供测试使用;
expect,用来实现断言,从而得到测试结果。
因此,Jest单元测试的一般流程即为:在describe函数里建立一个上下文环境,该环境竟包含了待测函数运行的必要信息,且所有信息都是确定的、可控的。在it函数里将待测函数引入环境使用expect函数设定测试参数和期望结果,建立测试。
3 Jest单元测试框架具体使用场景
Jest单元测试框架可以测试多种场景,下面举例说明。
3.1 测试前端某个函数的输出是否符合断言
首先给出待测函数例子:
需要测试该函数的正确性。
函数很简单,求两个数的乘积,对这个函数,可以建立测试用来检查结果是否正确:
这里用expect函数以函数f的返回值作为参数,toBe函数以期望的结果作为参数,如果两者相等,则匹配成功。toBe就是一种匹配器,Jest提供了多种匹配器,可以实现不同的匹配方案。
3.2 测试渲染出来的HTML页面的某个DOM结点是否符合断言,以Vue为例
首先给出待测试的Vue组件CustomCard代码:
需要测试出渲染出的页面类为“dd”的标签文本是否为“test”。
测试程序的主要代码如下:
该测试程序使用find方法抓取DOM,参数可以是css选择器,也可以是Vue组件的name
3.3 测试前端某个事件是否被触发
首先给出待测试的Vue组件CustomCard代码:
该组件中定义了一个事件action-btn:clicked,当点击组件时触发,现在要测试点击组件时是否触发了事件。
测试的主要代码如下:
这里创建了一个mock函数 event = jest.fn()作为触发事件后的回调函数,fn函数可以是空函数,仅用来测试是否被调用,也可以加入代码逻辑,当事件被触发后进行一些别的测试。
3.4 测试后台接口是否正确
前端调用后台接口是异步的,通常包装成promise函数,因此测试用例也是异步的,下面是一个例子:
待测函数:
该函数向远程服务器发送请求,请求参数为id=1,预期返回函数为字符串”ok”,则测试函数为:
可以看出,这个测试的写法和测试普通函数类似,但是其中用到了async/await关键字,这两个关键字在javascript中是处理异步的标准方案。
快照测试的流程是:当测试程序第一次启动时,测试把组件渲染成html文件后存放在本地,称为快照;测试程序再次启动时,将新生成的html文件与快照文件比较,如果有差别,则测试失败。由此实现了对UI组件没有发生非预期的更改的测试。