Unit Testing
单元测试概念
在计算机编程中,单元测试是一种软件测试方法,通过该方法测试源代码的各个单元(一个或多个计算机程序模块的集合以及关联的控制数据、使用过程和操作过程)[在组件库中对应的即为各个组件]以确定它们是否适合使用。
以上摘自维基百科
本篇主要介绍组件库的单元测试
为什么组件库需要单元测试
在编写高质量的自定义组件过程中,单元测试是永远避不开的一个话题。完善的测试用例是提高自定义组件可用性的保证,同时测试代码覆盖率也是必不可少的一个环节。
大家可以看到,在大部分优秀组件库源码中,都存在单元测试的代码编写。那么首先提出一个问题:为什么组件库需要单元测试?
在我理解下有以下几种原因:
- 保证代码的正确性。对于每次(自己/别人)代码修改,能够更有信心
- 能够定位排查隐藏bug,减少bug数目,避免回归等不必要的人力浪费
- 自动检测,可以做到一次编写,多次运行,节省重复测试的时间
- 对于组件库场景下有利于代码的重构,保证重构的安全性
单测的目的
单测的目的不应该是盲目提高覆盖率,而是要写关键代码的关键测试来减少bug出现的概率,以及防止bug回归
与一般库的单元测试有所不同,UI 组件库中的组件涉及到大量渲染和 DOM 交互,因此我们应确保:
- 保证组件的渲染稳定,如果有所更改,应当是预期中的。
- 保证组件的功能正常,事件执行、DOM、内部State等等;
- 保证组件代码逻辑被充分测试,代码覆盖率尽可能达到 100%;
单测核心思路
关注粒度、代码的边界值和核心逻辑,并非所有逻辑都需要编写单测用例
当组件对应逻辑修改后,单测用例也需要同步更新。粒度过粗,无法保障代码质量和稳定性;粒度过细,往往不堪需求变更之扰,付出不必要的时间成本。对组件的每一处细节都编写具体的单测用例,这是一件耗时耗精力的事,脱离了编写单测的本质
对于编写用例,仅需关注输入和输出即可
对于一个用例,我们需要关注其输入和输出,并且多次输出结果是一致的,这也是单测的基础。
单一测试职责
每个用例都是单一测试职责的
无需为依赖(接口返回值、依赖包…)编写测试用例
编写的关注点应为源码本身,主要确保源代码自身的逻辑正确性
如何编写组件库的单元测试
主要以 jest 与 @testing-library/react 进行介绍
安装配置jest
编写测试脚本
一般组件库的测试脚本是在组件文件夹中创建__tests__
目录,__tests__
目录用于存放测试脚本。
在目录下创建index.test.tsx
文件,在index.test.tsx
文件中编写测试用例
如:__tests__/index.test.tsx
1 | // 引入测试组件 |
关于快照测试
如上述代码所示.toMatchSnapshot()
会在执行测试用例时进行快照对比。快照测试能确保你的UI不会有意外的改变。在快照测试用例首次执行时,会在 __snapshots__
目录下创建快照文件,当后续再次执行此测试用例时,会将已有的快照文件进行对比。如果对比成功,则测试通过。
生成的快照代码示例(能够具体描述DOM渲染UI):
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP |
快照测试补充说明
视快照如代码。快照文件
__snapshots__
应当作源码对待进行提交(我们需要在代码PR
中审核快照,改掉测试快照失败时就重新生成快照的习惯,应定位问题后解决尽可能详细描述你创建的快照,以便于后续其他人理解
对于快照失败处理。如快照内容改动比较少,则同步修改快照文件内容;如快照内容变化非常多,可以删掉快照文件的内容,再次执行测试即可(需人工校验,谨慎对待)
相关Script
执行全部用例
执行npx jest
,jest
会自动扫描项目中所有的__tests__
文件夹,执行内部的用例。
如图所示能够看到这次执行用例的具体情况
执行指定用例
执行npx jest src/components/button
,src/components/button
为组件对应的相对路径,当修改了单一组件后为单一组件执行测试用例能大量减少测试时间
执行代码覆盖率检测
执行npx jest --coverage
,会在终端返回此次代码检测覆盖率情况,同时对应在项目根目录生成coverage
文件夹
我们可以打开(推荐使用VS Code的Live Server
插件)coverage/**/index.html
,在Web端查看对应代码的覆盖率情况
打开的效果如图所示:
在这里可以点击进入对应组件查看单行代码执行情况和次数