伪原创工具可靠不(【故事背景Up】前端测试的种类,简单过一下)
优采云 发布时间: 2021-09-24 18:25伪原创工具可靠不(【故事背景Up】前端测试的种类,简单过一下)
故事背景
Up的开发团队,由于缺乏测试人员(以下简称QA)的资源,更难保持质量。如果你很穷,你会考虑改变。近年来,Up 尝试并实践了各种前端测试方法。今天写出来和大家分享讨论。
前端测试的类型
简单看一下目前前端测试的种类,这不是重点,懂的同学可以跳过。
网上有很多文章介绍各种前端测试,单单SF里面就有很多好文章。我大致将它们分为两类。
1. 前端单元测试 (Unit Test以下简称 - UT)
2. 前端e2e测试
单元测试的第一点,大家应该都不陌生,即使你没有写过前端UT,那你也一定听说过mocha、jasmine、jest等测试框架。UT 的意义在于以更细粒度的方式测试我们的业务代码。写入的函数是为了测试函数中提供的方法是否可靠。
就像盖房子的时候,我们测试每块砖的密度、重量、长度、宽度和高度,确保每块砖都OK,不会有空心砖,这样才能确保建造出最终的产品。房子没有安全隐患
点 2 e2e 测试
e2e 测试是端到端测试。简而言之,就是利用一些工具库提供的API,利用代码来模拟终端用户在UI界面上的操作,比如输入、点击等。目前常用的工具有selenium、puppeteer、phantom、量角器(angular)、Nightwatch(Vue)等。
重点来了!我的团队是否需要前端开发和编写测试?
根据上一段的内容,我们分为2个部分来讨论
你需要编写“单元测试”吗?
上一段以砖头和房子的例子简单说明了单元测试的重要性,但这也只是说明了另一个问题,就是代码越基础,底层代码需要的单元测试越完整。确保它是可靠的,这样其他依赖它的模块才不会受到影响。前后端分离后,前端开发从系统架构的角度来看,其实就是一个站在食物链顶端的人。
第一个金字塔模型
从这个模型可以看出,前端作为消费者,站在了顶层。它是服务层的消费者。因此,UI层的可靠性只能通过保证Service层的健壮性和可靠性来保证。但是前端并不依赖于其他层,因为它已经站在了顶点。所以除了终端用户,我不需要负责其他层面。如果我不需要负责,我为什么要写UT?持不同意见的同学别着急,我们继续深入分析
第二个金字塔模型
前端也有自己的金字塔模型。当我们编写 UI 时,我们也会依赖底层代码。比如我们引入mvvm框架,需要用到lodash等util类库,需要用到公共组件。当然,我们可以自己实现这些前端。底层库和组件,但在大多数情况下,它们是合乎道德的。从github上找个明星,默认相信这些开源库已经完全UT,可靠。而我们90%的精力都花在了上层和上层的业务代码上。我们仍处于食物链的顶端,地位不可动摇。结论是我们还是不需要写UT。
什么情况下可能需要写前端UT?做一组真假题
1. 你写的是个util类,是会被其他类调用的那种?
2. 你写的是一个公共component,是会被其他工程调用的那种?
3. 你写的是一个开源项目
如果对以上3个问题有肯定的回答,就应该考虑写UT了。那么,UT对于前端重要吗?重要的!你想写吗?这取决于
我需要编写 E2E 测试吗?
看完上面的结论,严谨的同学可能已经跳起来指着阿普的鼻子说:“啊!谁说90%的业务代码不依赖?我们不在顶端。有客户就有上帝,这个业务代码对客户负责,所以为了这个业务代码的健壮性和可靠性,我们还是要写UT”
能提出这个问题的同学人很好,很显眼。你的出发点很好,但我们不妨换个角度思考这个问题。首先,单元测试的存在有一个前提,即提供者和它的上层消费者需要在同一个特定的消费者系统中。只有在同一个系统中,才有意义给provider写UT,否则不靠谱。的。很容易证明这一点。比如我用java写了一个util类。我肯定会在java的特定消费者环境中对这个util进行UT,因为它的上层消费者也必须在java环境中。前端mvvm框架的UT必须是基于JavaScript环境编写的,而不是其他语言,因为你的上层结构也是基于JavaScript调用的。当然,有人说它提供了restful api的服务层,虽然跟语言有关。环境无关,但要根据http的具体消费环境,或者说接口层面的测试已经属于集成测试的范畴了。
但是,前端业务代码与上层消费者——用户不在同一个特定环境中。它脱节了。GUI 显示在用户面前。用户单击、输入和拖动一系列用户事件。目视观察,实现顶级消费。不是调用F12,而是在控制台调用前端业务代码。所以即使你前端业务代码的UT做的很好,理论上也是不靠谱的。
那么,在这种情况下,如何保证业务代码对消费者——用户是可靠的和负责的?
说了这么多,终于带出了本文的重点——e2e自动化测试(以下简称Automation Test-AT)。我可以使用各种e2e工具来模拟用户的操作行为进行最终验收测试,所以我不想你和用户在同一个系统中吗?!等一下,也根据你项目的实际情况做几道是非题
1.测试团队是否兵强马壮 (基于人海战术的人肉e2e测试)
2.产品UI是否相对不稳定,经常大改 (改e2e case都来不及)
3.测试团队是否已经熟练掌握自动化测试技术,并已经运用起来 (QA来写e2e自动测试,理想国,前端就可以甩手了)
4.每一个迭代周期,留给QA测试时间是否充裕 (人肉e2e测试时间充足)
5.Service接口的测试覆盖率是否很高,后端UT的覆盖率是否很高 (底层建筑稳,隐患少)
6.每一个迭代周期,留给前端开发的时间是否很紧张 (前端写完业务代码,也要有时间写e2e代码)
如果你的回答超过2个yes,也许这个阶段不需要引入e2e AT,因为你背后有足够强大的测试团队或者有足够的时间来确保产品在交付给用户之前足够可靠或者由于产品的特殊性,不合理的项目进度导致无法实施e2e AT
第三个金字塔模型
e2e 测试(无论是人工还是自动化) e2e 测试是整个系统测试中渗透覆盖率最大的,它可以覆盖从基础到顶层的长距离。所以如果用UT来保证成品各个级别的可靠性,那么e2e就是用来验证这个可靠性的,它的作用范围还不止于此。
介绍 e2e AT
在团队中,如果QA资源稀缺,UI更改的频率不是很频繁,为了提高工作效率,提升产品质量,就要考虑是否引入e2e自动化测试来替代部分QA人工工作量。谁来编写 e2e 测试?第一顺位继承人,前端尽我所能!
有3个原因
1. 前端需要对自己写的业务代码负责,写UT又不可靠,那就只有写基与功能模块的AT了
2. 模拟用户操作,AT需要对各个DOM节点进行操作,前端对这个再熟悉不过
3. 有数款基于JavaScript的AT工具,学习成本低
e2e AT 帧的选择
硒
目前,市场上有各种各样的 AT 工具。Up 目前使用 selenium + jest。硒通常是不可触及的。虽然我们主要使用它的webdriver功能,但是选择了这种类型的驱动工具。up有个建议。不要选择针对某个自动化工具自带的前端框架,比如之前angular1时代up用的量角器。它的写法和UI框架强耦合,封装的API比起更原生的selenium也好不了多少,如果改天项目技术升级到Vue或者React之前写的AT案例基本已经过时了,所以最好选择更通用的AT工具。
笑话
以前,最多用过摩卡咖啡。虽然 jest 是为 react 量身定做的,但作为一个通用的测试框架,它也很容易使用。它还有一个更有用的功能,那就是快照。为什么说快照很有用?因为大部分手写AT的朋友都有一些经验——AT写作容易判断,但判断难。有了snapshot后,可以用2个snapshot进行对比,大大节省了获取dom节点文本的代码。只需比较两张图片,您就会玩得开心。当然,你自己实现jest的snapshot功能也很方便。如果想保留现有的摩卡或茉莉,可以引入快照功能。
e2e AT案例的测试范围
根据Up的经验,我认为e2e案例的范围最好以一个功能模块为最小单位,比如用户管理。在一个案例中,我需要涵盖四个基本操作:创建用户、查询用户、编辑用户、删除用户等。
//user.e2e.spec.js
const UserModule = require('UserModule');
const AuthModule = require('AuhtModule');
let userModule;
const userName = 'at_test_user';
beforeAll( ()=>{
new AuthModule().login();
userModule = new UserModule();
})
test('user:' + userName +'should not be exited', ()=> {
userModule.find(userName);
const image = webdriver.takeSnapshot();
expect(image).toMatchSnapshot();
})
test('user:' + userName +'should be created successfully', ()=> {
userModule.create(userName,pwd);
const image = webdriver.takeSnapshot();
expect(image).toMatchSnapshot();
})
//... other cases....
afterAll(()=>{
webdriver.quit();
})
为什么不用webdriver直接在spec里面操作dom呢?
建议大家给要测试的功能对象封装一个类,比如上面伪代码中的UserModule
//UserModule.js
module.exports = function UserModule(){
this.find = function(username){
//...
webdriver.findElement(xxxx).click();
}
this.create = function(user,pwd){
//...
webdriver.findElement(xxxx).input(xxxx);
//...
webdriver.findElement(xxxx).click();
}
// other operations
如果以后再写其他依赖 User 数据的 case,那么就在之前的地方调用 userModule 来恢复基本数据。这里就不细说了,OO的事情大家都比我更懂。
e2e AT 覆盖
在人员有限的情况下,什么情况需要一些AT,不需要的,或者不着急写的,以后慢慢补
1. 新功能不需要急着写AT,应该交给QA人肉测试,待功能上线后再慢慢补齐
2. 反28原则: 28原则是指最重要的只占其中一小部分,约20%,其余80%尽管是多数却不重要,但是写AT需要反过来,我们优先写那80%不常用到的功能,至于那重要的20%,由于经常被使用,它能不能工作一目了然,其实也是最健壮的,需要写AT来覆盖的优先级就不显得这么高了,反而那不常用的80%功能往往没有经过大量的用户测试,很容易在某次迭代中产生新的bug。
3. 优先写happy path,优先保证一个功能模块的主线畅通,再写边界值测试。
e2e AT的重要性
让我先谈谈回归测试。新功能上线时,我们需要对产品的旧功能进行回归测试,确保新代码的加入不会引入新的bug。通常在一次迭代中,QA 会花费大约 20~30% 的时间进行回归测试。这显示了回归测试的重要性。但很多情况下,由于项目时间紧迫或紧急发布,压缩和牺牲往往是回归。测试,e2e AT 可以只覆盖回归测试的一部分。如果你的AT case覆盖率越高,回归测试的覆盖率就会越高,生产也会越稳定。如果AT能够覆盖大部分回归测试,并且AT的执行效率是人工执行的数倍,QA的工作量就大大减少了。
e2e AT在开发过程中的位置(什么时候触发AT)
新代码合并到主线并部署到测试环境后,在进入QA人肉测试之前,是触发AT的最佳时机。越早发现错误越好。AT 和 jenkins 等 CI 工具可以很好地集成,并且它们不依赖任何特殊的插件。运行 AT 后,会自动生成报告。如果出现故障,会第一时间发送到邮箱暴露问题。美丽的
几句话总结
关于前端UT:业务代码不会写UT
关于前端e2e:建议使用e2e AT覆盖前端业务代码,并收录在开发过程中
另外,欢迎有不同意见的同学参与讨论!如果你有好的建议,请留言,毕竟是我家人的话,期待能引发技术火花。