单测是什么
单元测试时用来对一个模块、函数或者列进行正确性检验的测试工作,所谓的正确性,就是保证同一单元,在给定输入下,总能得到预期的输出
单测的好处
- 保证代码正常:设计合适的测试用例来测试代码,可以保证代码的正确性,提高对代码的信心
- 提升代码质量:耦合度高、功能不清晰的代码在做单测的时候是比较困难的,而单测的存在可以推动对代码的合理重构,对提升代码质量有帮助
- 进行回归测试:当需要对系统进行重构的时候,单测可以为重构的过程保驾护航,验证重构后系统功能的正确性以及保证系统的稳定性
- 全面测试场景:可以通过构建数据来触发不同的测试场景,对于一些人工测试时不便触发的场景,单测可以构造参数进行触发,支持的场景更加全面
- 帮助理解需求、熟悉代码:写单测的过程中需要梳理需求,从而进一步理解需求,同时好的单测也是不错的代码文档,有助于团队新成员通过单测了解代码的功能
测试模式
在软件开发中常见有两种开发模式,一种叫TDD,另外一种叫BDD,笔者在此之前听到比较多的是TDD,BDD也是在后面工作中听到后才了解的,网上有不少关于这方面的讲解,笔者这里就不做过多的讲解,只从自己的认识简单讲一讲
TDD (Test Driven Development 测试驱动开发)
在这种模式下一般会先写测试用例,或者是开发和测试同时编写,当对应的功能模块开发完成的时候,对应的测试用例也是开发完成。以笔者的工作经验距离,在一些版本迭代的时候会有一些技术评审,这时候前端开发可以对当前的一些功能或者模块做组件设计,一些可能通用的类或者方法会提出来,或者在开发的过程中发现某些功能或者过程可以抽象出通用的方法,这时候就可以提前先针对预设的组件或者方法先写好单测,或者在开发过程中抽取类或者方法的同时顺便编写单测用例,这时候通过单测的编写可以明确类或方法提供的功能,还有预期的输入和对应输出结果。
BDD (Behavior Driven Development 行为驱动开发)
这种模式一般是去到用户行为的维度,一般是在完成业务代码开发之后,以用户行为指导编写测试用例。以笔者的工作经验举例,在版本迭代开始的时候会有QA的同事进行用例编写,同时QA会将写好的测试用例(一般是以脑图的形式)发出来做一个评审,QA同事提供的这个脑图相当于是一个开发这边的测试用例参考,因为在需求和实际的一些交互还有一些边界问题可能在开发过程中才发现,所以一般会早业务代码完成开发之后才编写测试用例,避免重复的修改测试用例。
具体工作中的实践选择
TDD一般是偏向于类 方法 工具等维度,如果是开发一个工具包或者类、方法等,这种TDD的指导思想是比较适合的,不过TDD也是会偏向于开发过程理想化的一个,在实际开发中可能给到的开发时间是相对紧凑的,所以提前写单测或者一边开发一边写单测会占用一部分时间,所以不一定会进行。BDD偏向于用户行为的编写,会做整体业务模块的测试,这种在软件开发中很多时候是通过人工完成的,笔者见到的对用户行为的用例编写并不是很多。总的来说两种模式还是得结合着来,根据实际编写的是业务逻辑还是类方法等采用不同的模式。
技术选型
因为笔者平时开发的技术栈是用的react,这里就主要是针对react的单测进行学习
- Jest 单测的集大成者,Facebook出品
- react-tesing-library 提供一些操作react component的API,而且使用create-react-app脚手架生成的已经默认用react-testing-libray,可见官方也是比较推荐这个react-test
- enzyme 也是同react-tesing-libray相类似的一个库,react-tesing-library相对比较简单,对于enzyme我们这里不做介绍和使用
- pnpm 包管理工具,没有装pnpm的也可以用npm和yarn
- pnpx 同npx一样的命令行工具
- typescript 看个人开发习惯,笔者比较习惯ts开发所以选择
项目初始化
这里我们用pnpx加上create-react-app建一个简单的项目
pnpx create-react-app react-unit-test-study --template typescript
如果没有装pnpm的话可以使用npx
npx create-react-app react-unit-test-study --template typescript
如果不想使用ts的话,直接去掉上面的这个template参数即可,如下
pnpx create-react-app react-unit-test-study
创建完成之后create-react-app会有相应的提示,我们跟着提示进入到目录中然后启动项目即可
cd react-unit-test-study
pnpm start
可以正常跑起来,默认是3000端口,如果本地3000端口被占用的话,会有提示是否用其他端口,输入y即可,可以看到下面这个就算成功了
项目走读
笔者也是有一段时间没有用create-react-app,用的时候才发现加了不少新的东西,比之前简单的结构多了一些东西,也包括我们要学习的这个单测相关的东西,这里简单做个分析
package.json里面的包
- @testing-library/jest-dom 写单测的时候我们会有需要用到检查元素的属性、文本内容,样式类名等,这个库就是拓展了jest的能力,提供jest machers来增强能力,将使测试更具声明性、阅读和维护更清晰。
- @testing-library/react testing-libray里面关于react的部分,因为我们是针对react来做单测,所以要用这个库
- @testing-library/user-event 提供一些模拟用户与浏览器交互的事件,方便我们断言测试操作后预期的一些效果
- @types/jest jest的一些类型定义,因为这里用到了ts,所以加上这个包增加代码提示
文件说明
这里主要关心两个文件
- setupTest.ts 全局的测试文件,会帮我们引入一些全局的额东西,比如我们用到的这个**@testing-library/jest-dom**
- App.test.tsx 针对App.tsx的单测文件
看一下这个App.test.tsx
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
首先是定义了一个test,可以理解为一个测试单元,然后引入了App这个入口文件,通过render这个Api来渲染这个组件,因为我们做单测的环境里面实际上是没有浏览器环境的,所以我们需要通过拓展的这个render方法来渲染出一个组件,然后就是第二步,在页面中根据文案查找对应的元素,这里用到了screen这个范围,实际上我们也可以通过render返回值中获取对应的查询方法,例如getByText,这里先不展开细说,注意这里用到了正则表达式,最下面是一个断言,断言这个元素是存在于document中的。
运行单测
这里直接运行test这个名利即可
pnpm test
结语
到这一步我们的项目就创建好,也运行了预置的单测,后面就可以开始进入单测代码的编写
传送门
前端单测学习(1)—— 单测入门之react单测项目初步
前端单测学习(2)—— react 组件单测初步
前端单测学习(3)—— react组件单测进阶
前端单测学习(4)—— react 组件方法&fireEvent
前端单测学习(5)—— 快照
前端单测学习(6)—— 定时器
前端单测学习(7)—— mock
前端单测学习(8)—— react hook
前端单测学习(9)—— 覆盖率报告
前端单测学习(10)—— 状态管理redux
前端单测学习(11)—— react hook 进阶
前端单测学习(12)—— 性能优化
前端单测学习(13)—— 自动化测试