做为一个前端开发到底要不要写测试?来看看《前端要写单元测试?不存在的!那e2e呢?》

故事背景

Up所在的开发团队,因为测试人员(如下简称QA)的资源匮乏,较难保出品质量,穷则思变,近年来Up尝试和实践了前端的各种测试方法,今天写出来与你们分享,讨论前端

前端测试的种类

简单过一下目前前端测试的种类,这不是重点,了解的同窗能够跳过不看 java

网上介绍各种前端测试的文章很多,光SF就有很多好文,我大体归类了一下,主要分为2类react

1. 前端单元测试  (Unit Test如下简称 - UT)
 2. 前端e2e测试

第1点单元测试,你们应该不陌生,就算你没写过前端的UT,那你确定也听过什么mocha,jasmine,jest这类测试框架,UT的意义在于比较细粒度的去测试咱们业务代码中写的function,测试function里提供的method是否可靠。git

就比如造房子的时候咱们对每块砖的密度,重量,长宽高是否符合规范等数据进行测试,以确保每块砖都是ok的,不会出现空心砖等状况,从而保证最后造出来的房子没有安全隐患

第2点e2e测试
e2e测试就是端对端测试,简而言之,就是利用一些工具库提供的API使用代码来模拟终端用户在UI界面上的操做,好比输入,点击等等。目前经常使用的工具备,selenium, puppeteer,phantom,protractor(angular), Nightwatch(Vue)等等github

重点来了!个人团队到底需不要前端开发写测试?

根据上一段的内容,咱们分为2块来讨论web

需不须要写“单元测试”?

上一段举了一个砖头与房子的例子来简单阐述了单元测试的重要性,可是这也偏偏说明了另一个问题,也就是越是基础的,底层的代码越是须要进行完备的单元测试,以保证它是可靠的,从而保证依赖它的其它模块不会受到影响。先后端分离流行后,前端开发从系统架构层面来看,实际上已是站在食物链顶端的男人。后端

第一个金字塔模型

clipboard.png

从这个模型能够看出,前端做为消费者是站在最顶层的,它是Service层的消费者,因此只有保证Service层是健壮可靠,才能保证UI层的可靠。可是前端并不被其它层所依赖,由于它已经站在了顶点。因此除了最终用户我并不须要对其它层面负责,不用负责我凭什么还要写UT? 持不一样意见的同窗,稍安勿躁,咱们继续深刻分析api

第二个金字塔模型

clipboard.png

前端也有本身的金字塔模型,咱们在写UI的时候也会对底层代码有依赖,好比引入了mvvm framework, 要使用lodash之类的util库,要用到公共组件,固然咱们能够本身实现这些前端较为底层的库,组件,可是绝大部分场景下,都是拿来主义,从github上找一个星星多的,而且默认认为这些开源库都已经作了充分的UT,是可靠的。而咱们90%的精力都花在了更上层更顶端的业务代码上,咱们依旧是站在食物链顶端的顶端,地位无可撼动,得出的结论是依旧不须要写UT安全

哪些状况下你可能须要写前端UT? 来作一组判断题

1. 你写的是个util类,是会被其余类调用的那种?
2. 你写的是一个公共component,是会被其余工程调用的那种?
3. 你写的是一个开源项目

若是以上3个问题有一个确定回答,你都应该考虑写UT了。因此说,UT对于前端来说,重不重要?重要!要不要写?看状况前端框架

需不须要写E2E测试?

看了上面的结论,严谨的同窗可能已经要跳起来了,指着Up的鼻子说:“啊!谁说那90%的业务代码不被依赖的,咱们并无站在最顶端,咱们上面还有客户还有上帝,这业务代码是要对客户负责的,因此咱们仍是要为这业务代码的健壮可靠性写UT”

能质疑这个问题的同窗,很是好,很是秀,你的出发点是很好的,可是咱们不妨换个角度来思考一下这个问题。首先,单元测试的存在有个前提,就是提供者和它上层的消费者须要在同一个特定的消费体系里,只有在同一个体系里,对提供者写UT才有意义,不然这是不牢靠的。要证实这一点很容易,好比我java写的一个util类,我确定会在java这个特定的消费环境里来对这个util进行UT,由于它的上层消费者确定也是java环境。一个前端的mvvm framework的UT确定是基于JavaScript环境来写的,而不多是别的语言,由于消费你的上层建筑也是基于JavaScript来调用的,固然有人说提供restful api的service层,虽然跟语言环境无关,但它都是基于http这个特定的消费环境的,或者也能够说接口层面的test已经属于整合测试的范畴。

可是,前端的业务代码却和上层的消费者——用户,不在同一个特定环境里,是脱节的,展示在用户面前的是GUI,用户经过一系列的用户事件,点击,输入,拖动,肉眼观测实现顶层消费。而不是呼出F12,在console里把前端的业务代码把调用一遍。因此说即便你的前端业务代码的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

第三个金字塔模型

clipboard.png
e2e测试(无论是人肉的也好,自动化的也好)e2e测试在整个系统测试的贯通性覆盖率上来讲是最大的,它能够覆盖从地基到顶端的这一长串的范围。因此若是说UT是用来保证保证成品各个层级可靠性的话,那e2e就是用来验证这种可靠性的,而且它的做用范围运不止此。

引入e2e AT

团队中,若是QA资源匮乏,且UI变化的频率不是很频繁的状况下,为了提升工做效率,提高产品质量了,咱们就要考虑引入是该引入e2e自动化测试了来替代一部分的QA人肉工做量。谁来写e2e测试? 第一顺位继承人,前端当仁不让!

理由有3

1. 前端须要对本身写的业务代码负责,写UT又不可靠,那就只有写基与功能模块的AT了
2. 模拟用户操做,AT须要对各个DOM节点进行操做,前端对这个再熟悉不过
3. 有数款基于JavaScript的AT工具,学习成本低

e2e AT框架的选择

Selenium
目前市面上AT工具琳琅满目,种类繁多,up目前使用的是selenium + jest, selenium通常来讲是雷打不动的,虽然咱们主要使用的是它的webdriver功能,选择此类驱动型工具,up有个建议就是不要选择针对某种前端框架自带的自动化工具,诸如之前angular1时代up用过的protractor,它的写法对UI框架是强耦合的,且封装的API并不比比较原生的selenium高明多少,如若他日项目技术升级为Vue或者React以前写的AT case基本就废了,因此仍是选用比较common的AT工具会比较好。

Jest
以前,up用的是mocha,jest虽然是为react量身打造,可是把它当成一个common的测试框架也挺好用,它有个比较有用的功能就是快照snapshot,为何说快照很好用,是由于,亲手写过AT的朋友大多有些体会就是——AT写操做容易作判断却难,有了快照以后,就能够用2张快照进行比较,从而大大节省了取dom节点的text的代码,直接两张图一对比就玩事儿了。固然jest的快照功能你要本身实现也很方便,若想要保持现有的mocha或者jasmine同样能够引入快照功能。

一个e2e AT case的测试范围

根据Up的经验,我认为一个e2e case的范围最好以一个功能模块为最小单位,好比用户管理,一个case里我须要覆盖到:建立用户,查询用户,编辑用户,删除用户等4个基本操做。

//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();
})

为何不直接在spec里使用webdriver操做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

若是往后写其余case依赖于User的数据,那么就在before之类的地方进行userModule的调用来简历基础数据。这里不赘述了,OO的东西你们掌握的都比我好。

e2e AT的覆盖率

在人员有限的状况下,什么case须要些AT,那些不须要,或者不急着写,能够往后慢慢补

1. 新功能不须要急着写AT,应该交给QA人肉测试,待功能上线后再慢慢补齐
2. 反28原则: 28原则是指最重要的只占其中一小部分,约20%,其他80%尽管是多数却不重要,可是写AT须要反过来,咱们优先写那80%不经常使用到的功能,至于那重要的20%,因为常常被使用,它能不能工做一目了然,其实也是最健壮的,须要写AT来覆盖的优先级就不显得这么高了,反而那不经常使用的80%功能每每没有通过大量的用户测试,很容易在某次迭代中产生新的bug。
3. 优先写happy path,优先保证一个功能模块的主线畅通,再写边界值测试。

e2e AT的重要性

先说说Regression Test即回归测试,当有新功能上线后,咱们须要对产品老的功能进行回归测试,以确保新代码的加入没有引入新的bug。一般一次迭代中,QA会花费大约20~30%的时间进行回归测试,可见回归测试的重要性,可是不少状况下,因为项目时间紧迫,或者紧急发布等状况,被压缩和牺牲的每每是回归测试,而e2e AT正好能够覆盖一部分的回归测试,若是你的AT case覆盖率越高,则回归测试的覆盖率也越高,出品也就越稳定,若是AT能覆盖绝大部分的回归测试,而AT的执行效率又是人肉执行的数倍,那QA的工做量就被大大的下降。

e2e AT在开发流程中的位置(什么时候触发AT)

当新的代码合并到主线并部署到测试环境后,进入QA人肉测试环节前,是触发AT的最佳时机。bug是越早发现越好,AT与jenkins等CI工具能够很好的整合,也不依赖于什么特殊插件,跑完AT后自动生成report,如有失败则发送邮箱第一时间暴露问题,岂不美哉

几句话总结

关于前端UT:业务代码能够不写UT关于前端e2e: 推荐用e2e AT来覆盖前端的业务代码,并归入开发流程另外,欢迎有持不一样意见的同窗参与讨论! 若是你有好的建议欢迎留言,毕竟是我一家之言,期待能碰撞出技术火花

相关文章
相关标签/搜索