我的测试开发十年之路

目前在测试开发行业已经摸爬滚打了十年,一直忙于工作,基本没有多少时间可以静下心来进行沉淀。现在,终于有了个机会,可以对自己的测试开发生涯十年进行一次总结,希望这次能够写完吧。

文章较长,大致目录如下:

  1. CICD初识
  2. 接口测试框架养成
  3. 测试之殇 - 无尽的UI自动化
  4. 从2D到3D - 不一样的U3D测试
  5. 跟行业专家学习 - 虚拟现实国标起草之旅
  6. 沉迷游戏 - 用AI学习玩策略游戏
  7. 转型负责人
  8. 点了性能测试技能树
  9. 测试开发与编程
  10. 总结

(绪)

从毕业后,我干了两年的PHP开发,可能因为不是专业原因,也可能是因为天赋原因,遇到了一些瓶颈,在技术上始终没到质变的过程。机缘巧合之际,遇到了一个好领导Z总,他在简单面试过我后,就决定同意我转入到QA部,担任测试开发工程师,也给我晋升了一级,在第一年,领导开始给我定了CICD的方向,把项目的CICD给打通了,当时应该是2013年的时候,devops没像现在这么火热,但是因为教育系统的复杂性,大家都意识到,这玩意儿,没有CICD可不行,每天出问题,都是用户第一个发现。

于是我们开始研究CICD的技术方案,当时用的是jenkins和teamcity,为什么用两套,因为开发团队又有C#.NET帮,又有PHP帮(手动狗头,逃!),teamcity对C#显然支持更好,而PHP当时有xinc,hudson(如果我没记错的话),jenkins,当时jenkins从hudson出来后,社区活跃,所以选择他当然没错,所以一款产品火不火得起来,好的社区很重要。

当时CICD的流程,是先更新代码,然后跑单元测试后,跑端到端测试(所以感觉叫持续更新、持续测试比较合适,可能是CUCT),单元测试和工程代码是放在一起的,但是端到端测试,代码是独立的管理方式,这就导致两个流程没法很好的串联起来。

我于是用刚学的开发了一个ci_sync的同步工具脚本,集成到了jenkins,自动拉取端到端的测试代码,并对一些配置脚本进行分析,替换一些环境变量,并去除一些不必要的调试代码,其实就是类似autoconf、automake这类的构建系统,只不过不像autoconf那么复杂,我没有这块基础和背景,所以还是选择简单实现,采用大量正则进行匹配替换。这个实现很丑陋,所以我后面也开始学习一些类似语法解析的技术,来进行脚本的解析和处理。脚本开发完以后开始用起来,后面就开始一直埋头优化和维护这套脚本。但是,Z总找到我说,虽然我能力还行,但是距离他的期望,其实有挺大距离,他希望找到的是一个测试架构师,现在他不知道该不该把这个位置留给我。虽然我不知道这个架构师到底是个啥,但是还是默默答应下来,好的,我会成为一个测试架构师,事实上,我后来也看了《测试架构师修炼之道》,但是咱就是个社恐,理念可能略懂,但是要跟开发大佬们滔滔不绝,咱还是没这个底气。

(一)测试框架养成

上一节咱谈到了测试架构师,在我看来,实在也不懂这条路怎么走,后面应该是又一个机缘巧合,几个测试小组开始研究起了接口测试框架,大公司就是这样爱一起扎堆造轮子。我的大Z总知道了这个事,又出面了,搞了个workshop,叫上了部门的几个技术大牛,当然,好像也包括我,一起去PK接口测试框架用哪个。我有点头疼,你安排我做行,让我去争,我还是有点犯蹙的。不过,既然领导开头了,咱硬着头皮也要上吧。我的编程哲学其实是很不入流的,大部分人是先有鸡(规划)再有蛋(实现),而我遵循的是,这个水分子就是由H元素和O元素构成的,你拿HO还可以组成双氧水,你可以在头脑里有个大概的样子,但是你没法清晰定义他,就尝试着写把他组合起来看看吧。所以,我在这个过程中,我写了个http请求的lib,然后再把他放到unittest里,这个就是一个测试框架的雏形,这样对吗,好像对,也好像不对,跑能跑,少了点啥,unittest的报告可太丑了,不直观。所以,又找了个htmlrunner,把测试集扔进去,报告出来了,有点好看了,但是代码还是很丑,还有bug,所以我就把htmlrunner拆开来了,研究他写的啥,然后就加了下调用时长,blah...blah。由于我当时刚好参与的是基础设施的平台,叫共享平台,是一个可以提供各种基础设施服务,申请使用的平台,我就想着这些东西可是宝贝,意味着我们的框架可以测试他,也可以利用他,于是我加了mysql连接池、加了mongodb,加了casandra等等。其实后面,我还搞了分词库,用的搜狗词库,但这些有点脱离了框架的本质,所以其实我没有在框架介绍中包括进去。

随着加的东西多了,整理了下代码,画个分层结构,比如用例层、业务方法层、公共函数库、第三方依赖,再加一些日志装饰器等等,就挺唬人了,当然,最后这个框架被推广起来了,我又写了setup.py,进行打包,放到了自己的镜像中管理起来,这样,大家可以通过指定pip源,就可以更新安装。

当时框架的接口文档差不多这样吧:https://cleardo1986.applinzi.com/html/nd.rest

(二)测试之殇 - 无尽的UI自动化

接口测试框架其实用python来写,是最没技术含量的,因为python足够简单,库足够多,但是大部分测试开发其实是没多少底子的,有些是测试兼职写代码的,所以就挺适合他们。

轮到UI自动化,这里先说WEB,PC我后面再补充,大部分人做不好PC,其实我感觉方向错了,因为PC是操作系统强相关,你依赖的是windows的win32 API。(跑题了,逃!)回到WEB UI自动化,当时的王者是selenium,其实现在还是,只不过这破东西,就是一个接口测试框架,他的核心就是牛逼的http连接池,然后去调用chromedriver、gekodriver、safaridriver、Edge driver、IE driver。

我自己尝试编译了下chromedriver和Edge Driver,你会发现,人家这才是牛逼的代码,你直接绕过driver,触发对应的浏览器,稳定性一定会上一个台阶,当然,代价就是这个代码普通人看不懂,chromium的代码,堪称行业的C++工程典范,干测开的,你没时间去同时维护这么多,所以,自然而然的,基于selenium来打造一个UI自动化测试框架,就成了唯一的路,通过重试啊、等待啊,勉强能够发现一些问题。代价就是你要天天去看,为什么没跑过,哪里异常了。框架底层的大部分,都是在折腾这些事。

当然,我这种菜鸡,也是折腾这些。一开始,封装元素定位层,封装控件操作层,只要一个基类就可以搞定了,当时应该是selenium3,就pip安装下,指定chrome的路径,写一个drivermanager的驱动管理类,就可以把流程跑起来了。其实我做UI自动化的时间并不长,因为当时部门的重心还是放在了接口上。当时也没有pytest、allure这样的神器,大家对PO模式也是一知半解,所以整个UI自动化测试过程是痛苦的。

后面,来了个叫H2的测试开发大佬,他打字不快,但是编码逻辑思路很清晰,在测试开发经验上也很丰富,我记得他的一个理念就是反对在框架中封装过多的js脚本,因为对于端到端的测试来说,用户是不可能去直接执行JS脚本的,能模拟用户点击的,还是应该模拟。最后我们组的UI自动化测试框架由他使用java重新写了一遍,还加上了分布式执行,使用的apache mq,来接收消息,并触发用例脚本。这个架构基本是没啥问题的,但是稳定性的保证还是需要做不少工作,感觉适用staf这个分布式框架来托管脚本,应该是个不错的选择。总之,我得承认的是,我在WEB UI自动化领域,不算资深,但是在框架的理解上,应该也是正确的,毕竟实践才是检验真理的唯一标准,实践不够,只能说我的小脑袋,还是没法做到真全栈。

(三)从2D到3D - 不一样的U3D测试

不管PC端还是WEB端,其实我们做的前端测试,都可以统称为2D图形界面及其交互测试。但是随着图形显示器的快速发展,3D显示效果和性能都有着十足的飞跃。公司开发了一款3D编辑器软件,这款软件是我至今为止看过的内部开发的最复杂的代码。
做3D测试,需要在原来的2D界面增加一个Z轴,除了这个区别,其实测试点和原来的软件没啥区别。但是这个Z轴在很多方面增加了复杂性。原来的坐标操作,包括平移、旋转、缩放,包括一个摄像机位置,都需要专门处理。这里面涉及齐次坐标,欧拉角、四元数等复杂的概念。如果你是黑盒测试,你靠想象力测试也没啥问题(所以,黑盒测试比白盒测试就是简单在这里,你只有思维发散,专业理论不懂,也没什么关系)。不过,我一般不会满足于单纯的黑盒测试,所以我把这款3D软件涉及到的知识整理了下,大致可以分为游戏逻辑GameLogic、物体变换、颜色、光照、动画、粒子系统、纹理、碰撞、外设事件处理等部分,其实综合来看就两个大块,一个叫渲染系统、一个叫物理引擎,其中渲染的核心就是着色器Shader,我们公司有个岗位叫TA,也叫技术美术,就是专门研究这个渲染系统,算是美术和技术的桥梁吧。这个编辑器的开发原理,就是把Unity提供的各种能力,进行封装后,通过可视化操作,开放给用户,有点类似Minecraft。

对于这种编辑器类型的应用,用户使用场景繁多,基本没法遍历,因为是模型+行为的指数级,所以只能进行对偶pairwise或者正交表来设计用例。这里推荐机个很强大的工具,一个是微软的PICT,可用于生成pairwise用例,另一个是自动化操作模拟工具AHK,可以模拟windows上的按键操作,用来代替人工在PC端上点点点。通过这些工具,我们设计了一些用例组合,在这个3D编辑器上编辑后,打包生成一个可以运行的场景,但是,这个场景的性能问题很大,到底什么原因卡,比较难判断。我们当然希望能够把根因尽量分析清楚,我的排查思路是先对编辑器添加的所有的GameObject进行一次遍历,并确定其类型,然后逐步的把各种特效给去掉,这个过程需要有点耐心,在逐步分析后,我们发现,有很多不必要的特效被加了进去,比如加了多个多余的光源,还有一些地形的叠加、树木Entity(包括大量的树叶顶点),其实都是比较影响性能的。虽然U3D自身也替我们做了许多工作来帮助优化性能,比如摄像头画面部分渲染、遮挡剔除等,但是开发过程中,如果不注意对资源的使用,或者进行一些过度的计算,都会导致卡顿问题。

最后,其实资源一般都需要进行专门的检测,比如面片数、顶点数,我通用C++的一个assimp模型导入库来进行一些模型的加载分析,然后放到自己的scene中,去观看效果。对于我这种非专业开发来说,喜欢用朴素的实现方式可以让我清楚地知道我每一步到底在干什么。

(四)跟行业专家学习 - 虚拟现实国家标准起草

因为已经研究过一段时间的3D相关知识,刚好又赶上国家在大力扶持VR产业,都说一流的企业坐标,二流的企业做产品,这时工信部电子技术标准化研究院的王聪老师,刚好在负责相关的标准化工作。标准虽然不是强制性标准,但是对于企业来说,能参与进去,还是能起到一定的宣传作用。所以在领导的鼓励下,我们就积极报了名,并和王聪老师联系上,开始参与进这个标准的起草工作。

国家标准整个制定过程可比企业内部标准严格得多,国家标准的规定,除非是食品、安全相关,大都是指导性的,因为很多标准很难去统一量化,特别是软件行业,不同类别的应用,其实开发过程差异相当大,基本不大可能统一化。所以我们看GB/T 25000之类的,就是列指标和度量维度。所以在起草这个标准时,多次召集国家科研院校的专家老师和各大公司的技术大牛进行激烈讨论。最后,还是基于测试模型来进行定义,包括功能、性能、易用、可靠、易维护、可移植、兼容方面来对VR软件进行测试指标和方法的说明。这个标准的起草,其实对企业的测试意义可能不是很大,因为测试方案的制定,没有人会离开这几个维度,但是脱离标准进行测试,本身就是不对的行为,你可以围绕国标,去制定自己内部的一些标准规范,标准定出来了,才能执行测试,不然,根本不知道测试到底通没通过。而不是单纯为了配合开发,去拍脑袋,这其实对用户是很不负责的,只能说,项目的压力还是太大了,有时为了按时交付,就选择走捷径了,带伤发布。不过,对于国家而言,标准的意义其实是很重大的,比如有一类标准是关于技术细节定义的,类似OpengGL这样的,如果能够对这个技术细节进行充分完整的定义,那么我们在开发3D应用时,就可以都统一使用国家的标准格式,一个是涉及知识产权问题,一个就是国家内部各个平台的打通问题,如果标准写得不清晰,存在歧义,那么对以后国家项目的建设就会带来很多不必要的麻烦。

总的来说,标准最重要的是标准化的对象定义要清晰,你要标准化的对象边界一定要先划分清楚,然后才能围绕这个对象建立起标准体系,要做到逻辑严谨,一环扣一环,如果不是行业专家,真的做不来这个。最后说下,我即使参与了这个标准的起草,其实远称不上专家,专家的经验、经历、技术一定要达到一定的积累,而企业中大都比较浮躁,毕竟盈利和生存才是最重要的。但是无论如何,在参与过程中,认识了很多的行业大牛,知道了自己和专家老师们的差距,这点上对我个人还是很有收获的。

(五)沉迷游戏

其实我平常是不喜欢玩游戏的,玩游戏其实是很难的事情,一个是要动脑,还一个是要动手,比你写代码还难,写代码就是按顺序敲着字母和标点符号,但是玩游戏,特别是对战游戏,需要涉及到策略、操作、协作等等。能够对游戏进行测试,也算是对自己的一个挑战吧。除了测试,还想要加点AI的东西,这个靠我一个人肯定是搞不定的,当时我们是几个人进行了下分工,有个热爱AI的量化大牛TS,颜值与才华并存的研究生美女,还有一个大气豪放的周董。我们基本安装游戏操作库封装、图像识别、算法研究进行了分工。在这里面,我更多还是打个杂,因为对神经网络是完全的小白,不过,在做这个项目的过程中,还是算入了个门,学会了keras、QLearning的模型的使用,还用了下tessert的OCR库,最后在把同事训练好的yolo v5的模型导进来,在自动跑脚本的过程中,识别英雄人物后,进行一些操作,把棋局状态记录下来,设计血量为reward奖励,不断的学习对战策略。总体来说,这个项目没有达到预期的效果,就是对战能力几乎就是3岁小孩子的游戏水平。但是,我其实意识到,游戏算是一个状态机,只不过状态比较复杂,不考虑游戏情节推进的话,能够在debug模式下,把具体的状态抽象记录下来的话,很多游戏还是可以AI化的,只不过这个对大多数人来说,门槛确实太高了。

(六)转型负责人:背上外部漏测率

随着年纪的变大,部门人事变动,在项目中做测试技术的归属感其实是相对较弱的,因为项目的考核更多的会围绕BUG产出,用例执行,对于项目方来说,其实是接触不到,也感知不到测试开发的存在的,也就是说测试开发在部门层面可能很重要,但是在项目团队,其实很难达到核心的层次。因此,我有时也尝试着去当一个测试leader的角色,为了了解相关的项目管理和团队管理知识,我考到了pmp证书和scrum证书,基本上我参与的考试都是拿到了优秀,但相比研究测试工具来说,学习还是付出了较大的努力,通过的时候有那么一点小激动吧。管人管项目,其实是很累的一件事,我其实有时会比较缺乏自信(当然,我也不懂很多人的自信是怎么建立起来的)。当时对测试管理而言,我最怕的就是漏测,每次出线上问题,总是紧张得不行,当时我负责的是基础设施的项目,对高可用要求非常严格,而且还碰上了机房迁移,通宵了几个晚上,还是出了一些问题,因为涉及的组件颗粒实在是太多了,包括公司的所有软件项目,也导致我当月绩效被降了一档。我最痛苦的还有评下属的绩效,因为公司规定,是需要有绩效比例分布的,所以每次都会评出一些不好的人出来,然后就需要面谈,请喝下奶茶,缓和一些上下级的关系。在我们公司内部,会提供很多管理类的培训,比如其中一个叫“潜龙七式”,里面包括目标制定、任务派发,绩效面谈、员工反馈、插单处理、复盘等等,但是学完后,在实际应用中还是缺乏刻意的练习和使用这些技巧来帮助管理。

总的来说,测试管理是一项对沟通技能要求非常高的工作,更多的是偏文科类的,比如要建立质量体系,梳理流程规范,做好质量数据度量分析、以及牵头进行质量相关的复盘总结工作,进行PDCA,持续改进等等。

(七)性能测试技能树

这里的性能是指的服务端性能,在服务端除了linux,其实我了解的并不多,因为从事服务端开发,其实是10年前的事,如今Spring成了这一领域的王者,但是因为个人精力原因,一直没有投入时间去折腾这个,可能偶尔项目需要的时候,在idea上跑一跑,改一改旧的代码。不过作为QA来讲,服务端测试和安全测试应该是最有难度的两个部分。所以在公司性能测试人才流失的情况下,我自然而然的开始也学着做起了性能测试,在一个性能测试过程中,一般会包括性能需求分析、造数、性能脚本开发、性能负载机部署、运行性能脚本,收集性能测试结果并分析瓶颈,最后提供测试报告。

我在需求分析的时候,一般会找到业务架构师、开发负责人确认好这个系统的业务规模,比如是一个新的系统,还是在原有系统上的改进优化,这样我们才好确认压测的目标、造数的策略、测试时关注哪些指标等等。

造数是我觉得在接口压测过程中最为繁琐和讨厌的地方,因为我们这里项目用的服务太多了,有mysql、mongodb、redis、es、hbase、tidb,cassandra,在压测过程中,需要有一定的数据量打底,但是你如果单纯的插入数据,那可太耗时了,所以造数一般还是得依靠压测工具,这个环节其实我做得并不好,有时我就是找开发、找运维一起帮忙导数据进去,我一般会按照格式要求,写入到一些如json或者csv的文件,然后就交给他们,大公司里流程很规范,只要下个单,能够算好成本就好了。

我们用的是nGrinder,底层就是Grinder,这个平台支持jython脚本开发压测脚本,所以写脚本对我难度其实不大,就是把脚本提供的API给熟悉了就行,但是这里遇到了一个问题,在平台上调试脚本,真是太太太卡了,如果你模板改的不多,那就还好,如果你模板改动很大,那调试起来就相当耗时,所以我自己开发了一个grinder的模拟器,其实就是把他的API,在线下自己模拟了一遍,把他的HttpRequest改成了httplib,然后一堆header、response解析,按照格式重新写了下,这下调试脚本可快乐了,因为速度快了好几倍,再也不同经历漫长的等待了。但是,同时这也有个好处,就是遇到在服务器上跑不过,本地却跑过的时候,不好排查,因为环境只要有差异并且是你没有意识到的,就会误导到自己,比如,我就遇到一个因为header里的app-id其实不一样,但是我忽略了这个,导致和服务器上的结果不一样,排查了半天,因为我在迁移脚本时,把这个配置给漏了,并且只打印了body,没有考虑header,犯了这个低级错误,还好有性能组同事帮忙提醒了下。

负载机部署:grinder的部署应该是相对简单,主要是把代理脚本上传到每一台机器上,因为我使用的机器其实并不多,所以我其实没有去制定对应的自动化分发代理的方案,而且我们使用的虚拟机平台需要通过堡垒机专用的运维系统来访问,并且虚拟机一般不会反复部署。理论上,是部署一台,复制过去就可以了。

因为是在nGrinder上运行脚本,所以只要设置好VUSER的数量和并发递增策略,就可以开始跑了,因为我们是用的falcon收集服务器资源数据,所以在跑的过程中,只要确认压力有打进去,并发生变化,就可以了,如果是做的线上压测,还需要判断是否需要进行数据环境的隔离,避免污染正式数据,影响了一些业务数据统计和分析。

结果分析一般就依靠对应的图标,比如是否有突刺,报错日志,最好能够结合pinpoint进行一些问题的定位,如果是资源占用问题,那就比较好定位,如果资源占用一切正常,那么可能就发生了一些诸如死锁,或者一些错误结果被提前返回的情况,因为为了保证系统的稳定性,服务端其实会对异常做了很多降级处理,这种情况,其实TPS和响应时间都正常,但是报错率也会比较高。

这里针对的是http类型的请求,如果是websocket或者gRpc这类的,可能grinder就不是很适合,即使改造了,结果也不一定满意。

(八)技术人员真的会老吗?

首先,真的会老,所以公司很难成为你的家,除了体制内,等你老了,这个家可能就容不下你,这很正常,因为当这个家不能给你提供粮食时,你也会选择放弃,对不对?

其实不管是不是技术,除非自己的人脉能够一直稳定持续维护,不然都是会出现问题的。

所以你能做的,就是要么选择低压力的环境快速成长,或者就选择高压环境默默忍受,当然最理想的就是实现项目和成长的正向循环,比如,你在这个项目学到了自己想要学到的,你获得了成就感,同时项目也做大做强了。其实,就是诗和远方都有了。

(九)测试开发与编程语言

测试开发其实能够深入了解编程语言的机会并不多,因为在工作中涉及太多的工具和新知识,并且因为经常是在进度压力下要求二次开发交付,很多时候,我其实是凭着感觉在定位代码,并靠着百度,把自己的想法给实施了。但是任何技能,都是熟练到肌肉记忆才能够成为专家的级别。对于测试开发而言,能够得到这种机会的并不多,因为经常需要兼顾测试和小工具开发,除非是有专项研发的部门,并且遇到特别稳定的项目,可以让你长期专注某个领域。

我在几年的工作中,接触的编程语言就有php、python、java、c、c++、C#、javascript、es6、typescript,接触这么多,导致的一个问题就是很多语言用着用着就忘记了,涉及的生态体系,也基本没有机会深入研究,比如像Spring,其实包括非常非常多的体系,但是这么多年来,其实我也没啥机会钻研进去。

总结

在一家公司待久了,最大的可能就是不会被频繁的换环境,投入大量时间去熟悉业务和一堆很类似的框架,十年来,因为每年都会制定一些测试目标,服务不同的项目,所以有机会学习各式各样的技术,就是知识面可能会比较广,但是也有缺陷,就是编程技能,如果是语言强相关的,那么就可能出现经验不足的情况。有人说在大公司,一个萝卜一个坑,只会守在自己的一亩三分地。可能几年前业务好的时候是这样,但是近几年,大环境很糟糕,项目倒了一个又一个,但是好在我能够有一定的自主权,所以我还是能够坚持自己的人生规划,毕竟在我看来,干得久,比赚得多更重要。

posted @ 2023-09-05 18:22  cleardo  阅读(3331)  评论(6编辑  收藏  举报