软件质量体系建设--说说测试
软件质量体系建设--说说测试
有时候,猿粪到了,啥都可以说说.
一般IT建设的流程内,测试是非常关键和重要的一环,传说中,测试就是最后的守门员,重要性可想而知.
所以,现代的软件研发,不再把宝压在最后的测试阶段,而是准备建立完善的测试体系,让问题在最终上线前,大面积的暴露,在上线前达到稳定.
基于上述理念,在软件的研发流程里面,和质量相关的测试环节主要包含,单元测试,功能测试,非功能测试三种情况.
单元测试
执行单元测试的角色一般是开发.让开发做测试,一般来说开发是不愿意的.
提示
开发的职责是创造,需要把没有的东西创造出来.所以,从性格上来看,开发一般比较奔放,思维跳跃性较高,但是缺乏稳重,对重复的事情很容易感到厌烦.
但是,如果是从发现代码中的问题的角度,开发还是有点兴趣的.所以,单元测试,侧重点在于
- 让一个极小的功能(可能是一个方法)运行起来,验证输入和输出的准确性
- 检查过程中的代码覆盖率,确保大部分的代码分支都已经执行
- 保证可重复执行
一般的大厂都会设置SQA的角色,就专门检查每个项目组,单元测试的情况,一般检查2个指标
- 整体代码覆盖率
- 代码复杂度
满足了2个指标,SQA下达允许测试的指令,开发转入测试流程.所以,SQA对于开发来说,那就是人见人烦的角色,站在开发的角度,SQA就知道每天提一些规范性的问题,对于内部的业务逻辑完全不关心.SQA在研发团队内部,一般都和测试一起吃饭,如果哪天SQA和开发一起吃饭,那肯定是有奸情了.
单元测试怎么做
单元测试说起来也简单,做起来就比较难了.如果随便看看我在gitee上分享的代码,里面都有单元测试,一个牛逼的开发,单元测试一般是作为对自己的基本要求.
一般单元测试都是分层测试,controller,service都是分层测试的.
警告
我们不会模拟一个url,然后模拟运行服务进行测试的.现在springboot中所谓的接口测试,都不应该由开发负责,而是由功能测试覆盖.
因为一个controller内部足够简单,那样的测试根本没必要.
如果一个controller内部的结构很复杂,那样的测试也根本没效果,根本没有覆盖率可以看,只知道这个请求测试过了,有问题也不知道哪里有问题,唯一对开发有利的就是可以比较好的本地调试.
为什么要分层,因为复杂的业务逻辑,我们应该大量的使用mock,保证方法的输入和输出在某些数据情况下的正确性.一个url方式的测试,无法覆盖到数据的复杂性,而且需要依赖本地服务的启动,不满足测试案例可以重复执行的要求.
一个完整的测试case,一般需要造数据,构建mock,调用方法,验证结果,删数据等步骤.

最后我们需要看看当前测试的覆盖度

这边推荐一个eclipse插件,eclmma,这个插件计算的覆盖率和sonar里面计算的覆盖率不一样,这边的往往覆盖率偏高,sonar里面覆盖率偏低.
功能测试
功能测试这边又是另外的景象.主要执行人是功能测试人员,这部分人员一般不被技术部门待见,因为技术含量最低.
功能测试中,所有的接口部分,目前都已经被自动化所代替.一般依托于各种测试工具,发送HTTP报文最终验证HTTP响应的结果.
功能测试中的页面部分,移动端一般是使用appium,录制各种脚本执行,验证体验不太好.
剩下一部分,就是PC端的功能页面.在2015年左右,曾经兴起一波基于selenium,基于各种脚本的自动化测试方法,最近几年实现下来,成本实在太高,招聘开发来写selenuim脚本,那就是纯粹的浪费.而且对于自动化测试中的测试数据和脚本的关系理不清,经常因为数据问题执行不下去.
说一下我这边的观点吧
- 凡是通过coding方式编写的测试用例,本质上是把开发人员当做测试人员,最主要的问题,进度无法控制,人员的成本也无法控制.一定要采用录制的方式而不是编码的方式,才能给测试人员进行推广.
- 自动化的根本在于数据的绑定,数据会固化在测试案例的脚本里,数据库里面,如果只有脚本没有数据库,测试案例是无法执行的.不管是界面自动化还是接口自动化,只要是自动化,就需要关注数据绑定.
- 测试人员的职责变化,如果整体上测试回归已经完全脚本化以后,测试人员的职责会变化为,维护数据和深挖业务场景的案例
- 自动化测试,不要只停留在工具选型上,工具在其中也不是最主要的考量.最核心的是效率,在这个流程的研发过程中,无论是开发流程还是部署流程,只要不满足整个流程的自动化,都要跟随着调整,说的委婉一点,逢山开路,遇水搭桥,说的凶狠一点就是神挡杀神,佛挡杀佛.
所以,如果各位对PC端的界面自动化感兴趣,推荐一个开源框架UIRecorder,再结合case管理工具和数据管理,可以方便的录制脚本和执行脚本.
建议通过jenkins来执行数据,执行UIRecoder的脚本.在UIRecorder的社区里,已经有不少自动化测试的例子,是通过录制脚本,然后使用jenkins驱动实现的.
如果已经实现了界面自动化测试,回头再看看测试人员的职责,是不是发生了变化.
非功能测试
非功能测试,是测试里面比较有技术含量的东东,而且网络上很少有人能说清楚非功能测试要测试点啥.
什么是非功能测试,非功能测试到底要包含哪些东西???我们通过生产上的常见问题,分析下非功能测试的范围

非功能的范围在这张图上比较清楚,硬件问题,网络问题,依赖服务问题,生产可能的变动,稳定性问题和性能问题都属于非功能测试的范畴.
怎么进行非功能测试
不同的问题有不同的测试思路和方法,这边先来个整体性的测试思路.

对上图的一些测试思路做一些简单的说明
- 不管被测试应用是如何构成的,按照开发推荐的最佳实践来部署应用
- 对这个应用,针对其使用场景,构建前置应用或者后置应用(一般由开发进行编码),将被测试应用进行包裹
- 前置应用接受http请求,使用jmeter/LR,除了可以发送测试的调用外,一定要增加背景调用
- 通过对测试调用数据的收集,最终和被测试应用中的输出或者后置测试应用的输出,找到请求和输出之间的等价关系
- 在测试过程中,对被测试应用实施各种环境变动操作,比如断网,正常关机等等
用一个示例说明一下,假设被测试应用是一个记账服务,我们先构建前置应用,接受HTTP请求,发送记账请求,没有后置应用.在测试过程中,我们以10%*TPS为压力,向前置应用发送请求,在处理请求过程中,我们可以做一些操作,比如kill掉记账服务的进程,关闭网络,杀掉数据库等等,最终我们可以通过前置应用的记录和记账服务保存的记录中间形成一个数量关系.比如前置应用成功数小于等于数据库成功数.
在非功能测试中,一般有多少种操作可以做呢???

这是一个模板示例,代入被测试的系统的各种特征,就能得到非功能测试的各种场景和case
通过模板得出的测试场景和case,基本上能支持到项目开展的第一个周期的非功能性验证和测试,后续需要随着测试进度的深入,根据发现问题的类型,再次更新问题内容.
非功能测试的原理
非功能测试面对的都是几率性的问题.单纯的测试是无法覆盖几率的,我们需要使用几率对抗几率.所以,非功能测试是使用程序去测试程序.
思维方式
我们通过一个问题,来阐述一下功能测试和非功能测试在思路上的不一样 假设有一个应用程序,这个应用程序在被直接kill的情况下,有10%的概率下次无法启动. 请问我们需要用怎么样的方式来证明这个问题??? 按照功能测试的思维方式,我们应该先kill掉,然后再执行启动操作,观察结果. 这边会有2个结果
- 应用程序报错,结果在10%以内,所以皆大欢喜,我们测试出了应用程序的问题
- 应用程序没报错,结果在90%以内,这个时候问题就来了,我们上述的测试过程,能证明当前的应用程序是没问题的么???很显然,上述的测试过程是不严谨的,是无法得到证明应用程序有问题的.
那么如果非功能测试,应该如何来设计这个场景,从而能得到我们希望的结果呢???
很显然,针对概率问题,我们不能只通过1次或者几次操作的结果来评价一个概率上的结果,这个结果是片面的,我们只能让测试过程经历N次的大范围覆盖,才能证明最后的结果.回到我们的样例,我们需要依赖程序的力量,自动化的执行10000次,而且还伴随着不同的请求场景,最终的结果如果没有错误,我们可以得到一个结论在99.99%的情况下,应用程序被kill以后,能正常启动.
就像上面一个简单的猜想,需要设计场景,开发测试程序,部署环境和测试执行,非常消耗资源,我们是否还需要针对各种场景都要被覆盖到呢???这个就是优先级的问题,这边不加探讨.
抽象归类
在各种硬件故障类问题分类里面,我们会有很多硬件异常,我们是否需要覆盖所有的场景???我们是否需要模拟内存条损坏???是否要测试主板烧坏??
答案是比较明显的,在非功能测试的范围内,我们不应该模拟上述场景,有以下原因
- 各种硬件的损毁,从技术角度看,非常难以模拟
- 就算可以支持模拟,我们也无法确定是被测试软件的问题
- 大量的所谓的硬件错误在软件层面都已经进行抽象,都有等价的操作行为可以对应,这些工作量没啥意义
所以我们必须要对我们测试的场景进行抽象,抽象的基础就是一下几点
- 硬盘问题,不管硬盘是磁头损坏,还是盘片消磁,在软件层面来看,可以抽象为读异常和写异常,不同的损坏,影响的支持异常的类型,所以磁头损坏和容量爆满/权限不足在软件层面上,是一个问题,都是读写异常
- 从不同角度观察一台机器的硬件异常,CPU,内存损坏,网卡损坏
提示
如果程序运行在当前机器上,当前机器的硬件出现损坏,当前机器的操作系统就会出现异常,操作系统会停止运行,无法明确是被测试应用的问题
如果程序运行在当前机器的上游,当前机器出现损坏,对于外部程序来看,只不过是当前机器发送了一个通讯报文,没有得到响应,这种情况和上游应用程序被kill是等价的
所以在稳定性测试的常见套路里面,我们一般只对网络,读写做部分的模拟,其他的都是通过进程正常/异常的kill来等价操作.
但是在日常工作中,非功能测试往往会被要求:"所有的场景都要覆盖",这个是对工作量和工作重点完全不理解的条件下做出的决策,下面就来讨论工作重点.
MVP(Most Valuable Part 最有价值部分)
在非功能测试的整个过程中,所谓的通用的非功能测试模板套用,只是很简单的一部分.通过套用模板得到的测试场景只能支持第一阶段的非功能测试(应用刚刚开发完,对于实现和使用不完全熟悉,但是要保证当前的基本功能可以顺利上线),通过简单的系统操作将这些浅显的bug被清除掉以后,应用需要进入深水区,在这个模板里面就体现为"白盒测试".
这边的"白盒测试"是需要按照对外承诺的功能来看实现原理,一个功能一个功能的拆分,一段一段的实现去看,并设计场景,每一个承诺的功能点,每一段被拆分的实现过程,针对性的设计正向和反向的场景.
"白盒测试"不但要对程序自身的实现负责,还要分析当前的程序在被使用时候,假象被使用/调用的场景,模拟调用的上游和下游的各种情况和问题.
"白盒测试"还要不断的收集上线以后的生产问题,对产生的生产问题进行深入分析,定位到具体的原因和代码,并固化为非功能测试case.
"白盒测试"要对程序内部使用的组件进行持续跟踪,更新了什么功能,怎么实现的,修复了哪些issue,甚至组件是不是有新的使用方式和新的使用场景.
这部分的工作,需要相对高端的人,需要能沉下心一步一步的分析,甚至需要一遍一遍的试验,所以这也是为什么产品研发困难和骚钱的地方.
写在最后
本文基本上写清楚了在IT系统建设过程中,各个环节的质量把控的点.中国的软件被认为质量不高,一方面是由于软件开发企业不愿意投入成本进行测试,另外一方面也是技术决策者对于质量的漠视和本身的不专业.
希望本文抛砖引玉,能给软件质量提供一点点的帮助.
