Cypress前端测试左移分享

3,472 阅读12分钟

介绍

本文主要内容:讲开发人员在编码阶段用Cypress编写前端测试,做到测试左移。

Cypress是一个重前端的测试框架,可以对前端页面、前端组件进行简单可靠的测试,带给开发人员轻松愉快的测试体验。Cypress可以使用电脑已安装的浏览器进行测试,如下图Cypress识别到我的笔记本安装了ChromeEdgeFirefox,也可以使用其内置的Electron进行测试(CI流水线上就直接用Electron跑测试用例)。

image.png

image.png

Cypress支持链式调用,封装了很多好用的API,并且具备完整的TypeScript提示,官网文档详细。

image.png

writing-tests.gif

业务都做不完,为何还要花时间用Cypress写测试?

Cypress给项目带来的价值:

  • 缺陷前移
  • 质量后盾
  • 提升个人能力

缺陷前移

什么是缺陷前移?

简单理解:缺陷前移就是在前期阶段做详尽的分析,采取好的措施去尽早地发现不合理的地方,尽早地暴露问题,促使团队更早地识别修复缺陷,这样后面出问题的几率就会越低,效能越好。编码阶段的措施可以是完成业务开发的同时产出测试用例,尽可能保证所有的代码都被测试到,所有的业务流程都能被测试用例覆盖到。

为什么要做缺陷前移?

image.png

如上图,项目修复Bug流程简化版所示,前期修改Bug很简单,开发自检出来有Bug,自己改代码修复,然后上库代码即可。后期修改Bug就会增加很多很多前期没有的环节了:

  1. 开发需要根据测试人员描述去复现Bug,可能需要自己构建复现的环境,Bug可能是必现的,可能是偶现的,如果复现不出来,还需要找测试人员沟通,让测试人员复现。从这一点可以看出,前端测试属于正向追溯,开发人员可以直接把问题复现,直接看到用例的代码执行细节,方便进行问题定位。而后期修改Bug属于逆向追溯,盲目性和工作量都是大大增加的。
  2. Bug解决得慢、后期Bug数量多都可能会阻塞项目进度,导致项目延期。
  3. 修改好Bug后,开发人员还要提供代码改动点,评估改动关联影响,给予测试人员测试建议。
  4. 修改好Bug后,还需要分析Bug产生的原因,开发人员需要对Bug负责任,转交给项目负责人审核。
  5. 测试人员需要重新构建新环境进行Bug修复验证,需要对Bug进行测试发散,如果Bug没改好,或者改动引发了新问题,还需要让开发人员重新修改Bug,重新走一系列改Bug流程。
  6. ......

Bug越到后面抛出,项目中人员所付出的时间也就越多,项目所承担的风险也就越大。基于Cypress做缺陷前移,在开发阶段写组件测试、e2e测试,在前期就把问题测出来,而不是等到后期才测出,缺陷前移率越高,项目的健康度、项目的能效也就越好。

质量后盾

开发代码上库前一般会有CodeReview、代码走读等机制去严格把关代码的质量,CodeReview、代码走读机制都是以为主体的保障,CodeReview的效果好坏会受人的当前状态和人的技术能力水平影响。比如一个人粗枝大叶,看代码不够细心,或者这个人感冒发烧、失恋、基金亏损导致头脑不清醒,CodeReview的效果都会大打折扣,项目的质量不能仅仅通过CodeReview去保障,而前端测试是以机器为主体的保障,机器不会受情绪影响。

相信你或者你身边的同事都遇到过,编写代码改了好几个文件,然后上库代码的时候,忘记提交其中的一个文件,执行报错影响基础功能,合代码时没发现,等到测试人员反馈,等到被投诉时才知道自己犯了这么一个低级错误。假设CI流水线上有前端测试去保障基础业务功能,这种低级错误一般都可以在合代码跑流水线的时候暴露出来了。

针对改代码漏测场景、改老问题引发新问题,可以通过提高前端测试的覆盖率来保障基本的业务流程跑通、业务功能不出问题。

组件测试可以反映出你的组件封装得好不好用,如果你的组件不好用,测试代码写起来肯定也是偏向复杂的,上库代码审核的时候,CodeReview的人也可以通过你写的测试用例理解你的代码,拥有前端测试用辅助的CodeReview效果肯定会比没有的好。

项目迭代积累下来的测试用例,可以用来支撑未来模块的重构优化、项目的架构演进。

升级第三方库对项目的影响面广,比如升级vue@2.5vue@2.6,如果有问题,开发人员是比较难提前感知到的,如下图测试小姐姐晚上八点半还去找开发小哥,因为有个页面之前功能是正常,现在突然变成不能用了。测试小姐姐埋怨开发小哥偷偷改代码,开发小哥很无奈地表示是组件库升级引发的问题,假设当时有前端测试保障,那就能在升级第三方库的时候测出来这个基础性问题了,测试小姐姐和开发小哥也就不用那么晚还在加班。

image.png

提升个人能力

懂前端去做前端测试是一个优势,而测试与前端属于不同的领域,需要自己折腾,自己学习很多东西:

  • 项目引入测试框架,Cypress集成到CI流水线上,肯定会遇到很多问题,比如内网代理,测试框架与技术栈的冲突......在解决这些问题的同时锻炼了你的解决问题能力
  • Cypress有自己的API封装、有自己的插件,如何使用Cypress编写用例?如何用Cypress测试一个组件?如何测试TypeScript的类型声明?你在学习新知识、实践新知识的同时也锻炼了你的学习上手能力
  • 如何基于UI组件库、基于项目去封装好用的测试API?如果做好大型项目的e2e测试和组件测试?这可以锻炼你的设计能力
  • 测试框架的选型如何做选择?选Jest还是Cypress?这可以考察锻炼你的预研能力

当你把Cypress很好地集成进项目里面时,想必那时候你的能力也成长了许多。

如何使用Cypress做前端测试

  • 测试设计
  • 实践建议
  • 调试技巧

测试设计

先别心急直接写测试,要先想好项目怎么测,想好测试的策略再行动。这里提供一种可行的测试规划设计:

  • 版本前期做到测试用例覆盖业务的主流程,版本后期持续沉淀更多的测试用例,比如对一些边界场景下产生的Bug,补充相应的测试用例。

  • 对于迭代很快、生命周期又短的页面(如商家活动页、运营页),允许不做前端测试。图表组件一般交互性不强,代码不会很复杂,也可以不对图表组件做前端测试。

  • 前端开发者在写测试用例时,需要尽可能不去依赖公共组件的DOM结构、内部封装细节,假设你写了200条测试用例依赖了弹窗组件的DOM结构细节,有一天组件库升级修改了弹窗组件的DOM结构,到时候你就需要手动修改这200条测试用例,改起来十分痛苦。得益于Cypresscommand特性,开发者可以对公共组件库的组件行为、组件断言进行二次封装,做到开发者在写测试用例时尽可能使用封装好的command,不需要去关注组件的内部细节。

image.png

  • 大粒度测试结合小粒度测试,大粒度测试业务流程,小粒度测试相对独立的组件。

我们在写测试用例可能会有一种感觉,就是你发现要测的东西测重复了,比如你在子组件里测了这个功能,然后你在父组件里又把这个功能测了一遍。为了更好的测试效率和测试效果,我们要对前端测试区分粒度。

大粒度通常是页面级别的,干扰项、依赖项多,依赖接口数据,依赖他人的组件。干扰项和依赖项都需要去做mock。运行时间上,大粒度测试耗时会比较久。在业务没有变化的情况下,假设我们对代码进行重构,我们是不需要去改动大粒度测试的测试用例代码的。大粒度测试的标题可以与需求点、QA测试点一一对应起来,格式可以参考:test('已知xxx,进行xxx,期望xxx', () => { /** 用例代码 */ });

小粒度测试通常是针对单一组件、单一函数、类级别的,干扰项很少。小粒度测试运行速度很快,如果模块重构,相关组件的测试代码很可能需要被一起重构掉或者重写掉。小粒度测试的标题对应组件的实现细节:test('prop username work', () => { /** 用例代码 */ });

实践建议

image.png

  1. 对于组件测试,不需要测试组件内部实现的API,使用组件时内部API对开发人员是隐藏的,我们应该测试组件的使用功能,vue组件一般是测试传入的propsslots,测试对外暴露的API,像浮层类UI组件可能还需要测试父组件销毁时,浮层类组件是否跟着销毁。如果项目对无障碍性有要求,还需要测试组件的无障碍性。
  2. 不要把所有的单测代码都塞在一个测试用例里面,这样会降低阅读性和维护性,而且还会降低单测运行速度,适当拆分成多个可以做到并发运行单测。
  3. Math.randomnew Date等尽量不要在单测中使用,因为这些API带有不确定性,应该使用固定的具体值,我们要尽可能保证测试用例不管运行多少次,每次运行它的前置条件的完全一致的。
  4. 测试代码不完善导致测试是通过的,但是功能是有Bug的。

假设你现在要实现一个需求:计算a的b次方。 左图是期望实现,右图是你实际做出来的错误实现,计算a的b次方变成了计算a乘以b。

image.png

然后你的测试用例是这么写的:

image.png

测试代码是通过的,并且测试覆盖率达到100%,你天真地认为很完美,但是其实功能是有Bug的。测试覆盖率达到100%并不能代表覆盖到所有的使用场景,建议根据使用场景去编写测试用例:

image.png

对应到vue组件的测试用例,就是可以通过setProps去切换使用场景:

image.png

调试技巧

如何指定执行某一个组件的单测?

image.png

image.png

通过test.only去执行组件指定的那一条测试用例:

image.png

落地效果

CypressVitestJest不同的一点是,Cypress不是基于jsdom测试,而是基于真实的浏览器、Electron进行测试,给开发者提供了每一步测试步骤的快照,开发者也可以对页面进行操作,查看浏览器控制台,测试体验满分十分,我给九分,少一分是为了不让Cypress骄傲。

image.png

CI流水线上的执行截图:

image.png

以前我们想要查看一个组件的预览效果,需要查看组件的源码,进行代码分析,需要找出这个组件使用的页面,有时候不熟悉业务或页面隐藏得比较深,找起来就会比较费劲。Cypress的测试用例可以看作是组件的Demo文档,新人接手模块,只需要执行一下这个模块的测试用例,就可以看到组件的效果,Cypress的存在降低了新人上手成本,项目的新人友好度+1。

引入Cypress不到两月,就已经测试发现了好几个组件的历史遗留问题,立即修复,新模块开发也可以帮助开发者自检,测试出来一些问题,很好地发挥了缺陷左移的作用。

带来的问题

Cypress接入项目是会增加使用成本的,不同的测试框架,API都存在差异,前端开发人员需要学习上手Cypress框架的框架理念、框架API。

在编码阶段让开发人员写测试用例会增加开发人员的工作量,但是不会加工资,开发人员评估工作量任务排期的时候,需要把前端测试的工作量也计算进去。

一些防抖节流操作可能导致测试用例偶尔挂掉、偶尔通过,排查这一类问题时费时费力。

最后,即使接入项目会带来一些小问题,但是瑕不掩瑜,Cypress这么香,快点PUA你的小组成员用起来吧!!!