相信有相当一部分前端人对于自动化测试是知识盲区,很少会有前端去写测试用例,比如我(不好意思啦~)。今天这是一篇扫盲文,纯是基础,大神绕过。
前端开发因其特殊性,快的一周会迭代一次,所以测试用例貌似是在浪费时间。但实际上,测试用例的作用还是蛮大的,尤其是那些流浪大且长期保存的页面。
下边我们来科普一下自动化测试的分类、实现框架及方案以及如何编写测试用例。
单元测试
针对代码中各个单元进行编写的测试用例,比如前端代码中的每一个工具方法都可以作为一个单元,对应一个独立的测试用例,通常会使用功能单元的方式来确定粒度。
常见的模拟操作分为:Fake、Stub、Mock、Spy。
一套完整的能够满足实际需求的单元测试方案,要包括以下几个功能:
断言
Jest 提供了注入到全局的 expect 风格断言(expect(1+1).toBe(2)
);
Sinon 提供的则是类似 NodeJs asserts 模块风格的断言(``sinon.assert.pass(1 + 1 === 2)`);
Mocha 则不绑定断言库,你可以使用 asserts 模块或者 Chai 来进行断言;
模拟功能
对象的 Spy: spy机制可以监视一个真实对象,对其进行方法调用会执行真实逻辑;spy也可以打桩指定的方法。
Mock:使用mock对象,访问对象方法不会执行具体逻辑。指定需要mock的类型类(接口或者实现类),生成 Mock 类,其中所有的方法都不是真实的方法,而且返回值都是NULL或者Empty。
函数的 Stub:又叫桩函数,存根函数,用一个桩函数替换一些接口函数,用于测试当前函数的特性。stub替代子模块(某些特定功能模块)的模拟函数或模拟类。
用例收集
编写测试用例同需要基于功能单元区分,常见的方式就是 describe
收集一个功能单元,内部又使用 it
/ test
来进行功能单元各个逻辑分支的验证。比如:
describe("运算功能单元测试",function(){
it("加法函数测试",function(){
var add5 = add(5)
expect(add5(5)).toBe(10)
});
it("乘法函数测试",function(){
var multi5 = multi(5)
expect(multi5(5)).toBe(25)
})
})
测试覆盖率报告
这一功能常见的方式是通过 istanbul (1.0版本,2.0 更名为 nyc)或 c8 来进行实现,其原理包括代码插桩与使用 V8 引擎内置功能两种。另外一个常见的场景是输出其他语言格式的覆盖率报告(如 JUnit),社区也通过 Reporters 的机制为这些测试框架做了支持。
如果你对单元测试不熟悉,可以了解一下 Vitest,基于 vite,运行非常快,对 TypeScript、ES Module 有良好的支持。
单元测试是为了测试单个功能单元,集成测试就是为了测试多个功能单元的协作。
集成测试本质上就是对多个功能测试进行组合,依然可以使用上述单元测试方案。
一般情况下,我们的测试用例运行时是受限的,我们并不希望真的发起网络请求,或者是和数据库交互,以及 DOM API 的操作等。这时我们就可以使用一些模拟手段,特定模拟一个可以交互的对象,通过修改它的行为来检查预期的处理逻辑是否正确,这个模拟行为我们称为 Mock。
通常我们又将这些行为基于模拟对象与注入的模拟罗尼又分为三大类:Mock、Fake、Stub。
Stub
主要用来隔离其它的组件让单元测试可以正常的进行,我们不会对Stub来进行Assert。
Mock
用来和测试代码进行交互,可以说我们会针对Mock来写测试代码,也会对它进行 Assert来验证我们的代码
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XOwgj3eT-1663205256508)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/626b4e54ef5f4744893677a9daa9a8b2~tplv-k3u1fbpfcp-watermark.image?)]
Fack
就是伪对象,它可以提供一个 Fake 的数据库——比如一个对象,这样对数据库的读写就变成了对内存对象的读写,变得更加快捷和稳定。
另外一个常见的 Fake 场景就是定时器,常见的单元测试框架都提供了 Fake Timers 的功能支持。
看上面的概念可能还是有些云里雾里,因为那是后端通用的概念,现在来说说在前端的应用。
现在的前端项目,组件化是一个明显的特点,因此组件维度的测试也是必要的。在组件中,我们可以模拟这个组件的入参,观察其实际渲染的 UI 组件是否正确。
目前使用的组件测试方法与框架是绑定的,比如Vue 下的 @vue/test-utils
。
E2E 测试
俗称为端到端的测试,它不再关注内部功能单元的细节,而是完全从外部还原一个真实的用户视角,简单的例子:用户登录-搜索商品-加入购物车-编辑商品-结算商品的一系列交互,谁管你的登录背后隐藏了多少权限分级,商品货架分级设计得多么精细,只要这个流程无法顺利走通,那你的系统就是有问题的。
常见的 E2E 测试框架主要包括 Puppeteer、Cypress、Playwright、Selenium 这么几种。
Puppeteer
只支持 Chrome + Chromium 内核,但是不带断言库,可以加上 NodeJs 的基础断言库,实现一些非常简单的自动化测试场景。
Cypress
提供了无头浏览器,断言,GUI,以及 Web 下的各种 API ,然后你就可以完全模拟使用浏览器进行的一切行为。
时 Cypress 也通过代码插桩的方式支持了覆盖率报告相关的能力。需要注意的是,Cypress 只支持浏览器维度的配置,如 chrome(也支持chromium)、edge、firefox。
适用于PC。
Playwright
支持同时运行多个 project,这些 project 可以被配置为使用浏览器内核(检验 PC、桌面端场景),也可以被配置为使用内置的 devices 预设,来检验其在移动端的表现,这些预设包括了视口大小、默认浏览器内核(chromium,webkit,safari 等)等等。
想要进一步地保障页面的功能稳定性,监控平台(白屏,JS Error,404)这一类的存在也是相当有意义的。前端测试的知识量果然还是海量的,这里罗列的也不过是冰山一角,由于工作中用的却是不多,所以这也是我的知识盲区,有经验的同学可以推荐更多知识来共享学习。真诚希望更多的同学加入学习的阵营,一起加油!