测试开发技术(一)—— 测试设计

    笔者从事互联网工作已经满10年,其中主要经历是做测试开发,先后就职于阿里、百度等互联网公司,最近因为各种原因,想总结一下在测试开发这个方向上的经验,准备围绕“测试开发技术”写几篇文章。 文章主要是基于之前的工作和项目经验,以后端为主,希望可以给新入行的同学一些启发,有不对或者不够全面的地方也请大家留言指正。      

    目前互联网公司的测试开发岗位分两类。一类是专门负责测试平台、效率工具开发的岗位,这类岗位一般相对来说少一些。更多的一类是既要负责业务测试、自动化测试,同时也要去开发测试框架、效率工具来辅助业务测试。《测试开发技术》的系列文章里的测试开发主要是指后者,所以文章会以测试相关的内容开始,当然后续也会逐步涉及自动化测试框架、测试平台以及效率工具。

        下面我们进入正题,测试设计。

        测试设计是测试的灵魂,也是测试和测试开发人员的必修课。没有哪个开发人员可以说写过的代码没有任何 bug, 同样也没有哪个测试人员可以说从来没有漏测。测试人员要做的是考虑更多种情况,尽可能的验证系统的每个功能点,把带到线上的问题降到最少。而测试设计的目标正是这点。测试设计是项目测试整体的开始,也是测试整个过程的总纲,通常是一个测试人员对项目测试思路的体现。虽然不同的产品类的测试重点不同,不同项目也有各自的特性,但想把测试设计做好,还是有迹可循的。下面就从几个方向来介绍测试设计的思路。

一,正常功能测试

        正常功能测试是项目测试基本功,需要尽可能覆盖系统的全部功能点,对线上的质量影响也最为直接,通常可以由下面几个方面入手:

        输入数据

        系统处理流程和分支

        系统内部数据、状态和极限情况

        在细节里考虑用户习惯和基本常识

        考虑新旧版本兼容性

        下面具体说一下:

    根据输入数据的范围来做测试设计,通常来说可以使用边界值覆盖和等价类划分的方式来设计case。输入数据可以是用户提交的信息,也可以是接口调用的参数,这一点比较基础,测试人员基本都会有所了解,就不详细叙述了。

    根据系统的流程和处理分支构造case, 这一点就是要熟悉系统的处理逻辑,根据处理逻辑来构造case, 尽可能额覆盖所有的处理流程和分支,有的时候可能会和上面的根据输入数据设计的case有重合。

    根据系统内部数据和状态入手,主要是要考虑系统已有数据或者状态对系统功能的影响。比如,要考虑构造系统中有不同的数据类型或者数据量的case; 再比如,很多系统是有状态机的,设计case的时候就要考虑每种状态下,不同的操作会不会有问题。举个简单的例子,笔者之前所在公司的一个团队,一些经验较少的客户端同学测试手通讯录应用,只在通讯里加了十几条联系人,测试了通讯录打开、添加、和删除,这样测试是没有问题的,但忽略了一点就是通讯录里的联系人数量,正常手机通讯录联系人的数量一般再100-500之间,当然也有很少或者很多的情况,这就需要我们再测试的时候考虑联系人数量,正常测试应该把联系人控制再100-500之间,也要测试联系人达到通讯录上限的情况。另外,有些通讯里的信息可能不仅仅是电话号,可能有其他信息比如邮箱、qq、头像之类的,这些也都要考虑。

    在一些小的功能点测试细节里用户习惯和基本常识有的时候在反而容易被忽略,比如之前公司需要招聘一名外包测试同学负责一些HR业务相关的WEB系统,面试的时候有个问题:一个休假系统,功能主要是员工提交休假,然后一层一层的审批,最终审批完成把休假信息落库。功能测试重点是休假的审批流,各个节点的不同操作。但在提交休假的时候有个小细节,需要计算休假天数。这个细节具体需要考虑什么呢?需要考虑提交休假的开始结束日期如果包含周末、法定假日、法定假日调休的情况,也要考虑夸月、夸年的情况。参加面试的虽然是外包同学,但也都是做过2年以上测试的同学,而且这个细节跟技术无关,面试了4-5个人,只有1个人能考虑到。再比如,上一段里提到的通讯录测试,也是没考虑常识和用户习惯。所以在测试设计和测试过程中一定要注意细节和细节里是否有一些常识和用户习惯的问题。

    考虑新旧版本的兼容性,这一点主要是针对一些对原有功能改造或者新系统代替就系统,主要需要考虑的是向下兼容,新功能或者新系统一般来说要兼容原有功能或者原有系统。

    以上五点,虽然分开阐述的,但并不是让大家分别设计case,  更多的时候是需要整体考虑这几点来构造case。

二、异常测试        

        面试的时候,很多做过几年测试的同学,对于测试相关的问题正常功能case设计都答得不错,但很多人会忽略了异常测试,要么没有考虑异常,要么就是只考虑了输入异常。在实际项目中,正常功能的测试是基础,保证了线上功能没有问题,但异常测试也很重要,往往关系着系统的稳定性和用户体验。比如,在后端,异常可能导致系统崩溃和数据异常,如果流量和数据量比较大,数据修复往往需要投入很大的精力;在客户端或者前端,异常可能会导致展示不正常或者直接卡死,大大的降低用户体验。

        下面,我们就看一下异常测试需要注意的地方:

        1. 输入异常

        这一点应该是提到异常测试最先想到的,通过构造异常的输入数据来构造异常case,这里就不作叙述了。

         2. 系统数据异常

    数据的异常可以是构造DB的数据异常,可以是缓存甚至内存的数据异常,也可以是在分布式系统里数据的不一致。主要目的是为了验证当数据异常的时候,系统会不会崩溃,能不能捕捉异常并处理。

    具体怎么构造数据异常呢?系统数据无论是持久化还是非持久化的一般都是使用外部存储系统(如mysql\redis\ES等),这类比较简单,可以直接在DB或者缓存添加或者修改数据来达到构造异常。还有一种是数据是存在内存的,这种需要使用一定的技术手段,通过改代码或者单元测试来验证,还得具体情况具体分析,一般来说QA构造的成本比较大,可以通过RD单元测试来覆盖。

        3. 依赖异常

    依赖异常主要是要验证依赖的系统、模块或者环境出现异常是否会导致系统的问题。比如数据库挂掉、依赖的模块处理超时、网络抖动等。要针对依赖构造异常case,就需要先梳理系统依赖了什么,这里不仅仅是下游的模块、系统,也可以是运行环境(比如机器宿主CPU打满、IO异常等),甚至也可以是系统本身依赖的一些动静态的配置(比如白名单、配置文件等)。

    依赖异常的构造要结合具体的项目来看,有时候构造起来不是那么容易,所以不是所有的项目都需要构这类异常,要结合系统稳定性和异常处理的要求来确定是否需要做这类测试。

三、性能测试&稳定性测试

        性性能测试和稳定性测试一般都是通过压力测试来实现。由于是测试设计,这里只讨论要测什么,具体压力测试计划后面用专门的一篇文章介绍。

        1. 性能测试

    不是所有的项目都需要做性能测试,那什么情况需要做性能测试呢?一般有两类,一类是从无到有的新项目,需要做一次性能测试来做性能摸底;另一类是有比较大的重构、新功能、核心逻辑修改的时候,需要对比修改前后的性能数据。

        性能测试基本操作:

        1. 确认性能测试目标,收集线上数据(主要是线上实际流量的比例)

        2. 确定方案,准备压测工具、压测数据,构造压测环境

        3. 压测并记录性能数据

        4. 整理性能数据,产出性能分析报告

        以上4点的具体详情后续会在性能测试的文章里详细介绍,这里就不多做介绍了。

        在测试设计阶段,需要能该判断是否需要性能测试,以及确定性能测试的目标。比如有些系统,流量很小,没有并发请求,后续一定时间内也不存在增量,那就可能不需要进行性能测试。

        2. 稳定性测试

    稳定性测试跟性能测试很像,也是使用压测工具来进行,但目标不同。性能测试是通过压力测试得到系统的极限性能或者和上一版本的性能对比数据,而稳定性测试则是通过压测工具提供稳定或者变化的持续流量,来观察系统持续运行的情况下是否存在异常。

    项目是否需要稳定性测试?一般而言新系统或者新模块上线,都需要进行稳定性测试,其他项目一般因项目具体的情况而定。笔者的项目经历中除了有些在持续集成中引入以外,多数情况下性能测试和稳定性测试都是一起做的,一般是先做性能测试拿到性能数据后,再用安全流量持续压测更长的一段时间,来观察稳定性的情况。

四、上线步骤测试

        上线步骤的测试主要是为了保证上线操作的过程没有问题。需要研发同学提前提供上线的步骤,提前在线下环境或者预上线的环境里操作一遍,然后跑一些case确认操作没有问题。具体需要注意以下几个方面:

    1. 系统或者模块的部署操作

    主要指模块上线的具体部署操作。早期互联网公司一般是RD或者OP手动操作,但现在一般都已经使用标准化的平台发单或者流水线的方式自动化操作,所以基本不需要太关注。

    2. 数据的导入和修改

    项目上线经常会伴随着数据导入、数据库表修改、数据格式修复、数据补全等,一般是导入SQL、执行脚本之类操作,这些都需要在上线前提前验证。另外,要注意设计这类case要跟上线步骤顺序保持一致。

    3. 上下游依赖和流量切换

     在上面功能测试是里提到了兼容性的验证,但在实际项目中,有些是没有办法做到完全兼旧版本,所以需要上下游模块或系统一起改造。这类项目上线步骤就需要考虑系统或模块与上下游依赖的上线顺序,以及是否需要停流量、在什么时机切换流量。那么,在设计上线步骤的case的时候就要考虑这些因素,需要重点验证一下上线步骤有没有这方面的问题。

五、线上回归测试

    线上回归测试的设计正常情况下一般都是在测试case中选取一些高优case,上线完成后线上执行,进行回归验证,通常情况下比较简单,我们对这类就不多讨论了。这里主要讨论一些比较特殊的系统,需要特殊的方式做线上回归,我们这里通过例子来介绍一下。

    比如说互联网金融公司提供的信贷服务,贷款申请操作,如果在线上验证,风控系统会有记录,对这个测试人员真实的信用信息产生影响,而又假数据,风控通常是不能通过的。这类服务做线上验证做一次两次还好,但如果多次操作,一些统计数据甚至是人行征信,都会受到影响。所以不是所有的系统都能拿测试中的case直接在线上回归,需要通过一些策略和技术手段来完成。

    1. 通过模拟线上环境来实现

    在模拟线上的环境来上验证,其实不是真正意义上的线上验证,但只要能做到尽可能跟线上环境一致,就可以起到一定线上验证的效果。这套模拟线上的环境,依赖可以直接使用线上的,数据可以从线上同步或者验证前全量导入,只有在一些特殊地方采用mock。比如前面说到的信贷风控,数据库数据可以从线上导入, 依赖服务可以直连线上,为了不影响征信,征信服务可以mock掉,这样除了征信,其他的跟线上都是一致的,就可以起到线上验证的效果。

    2. 特定数据或者流量标注

    流量标注就是在正常请求里加一个特殊字段来标识是测试流量,或者是在已有字段里增加测试流量的特征;特定数据其实跟流量标注一样,是用一组特定的数据来测试,也是为了明确测试流量,放在信贷风控的例子里就是特定某个人的数据来作为标识是测试数据。

    不论是流量标注或者特定数据,在线上验证都需要对线上的系统或者环境进行改造。通常方法有两种:一种是需要研发同学在系统上改造,对测试的流量进行特殊处理;另一种只适用于调用外部依赖或者模块间调用的情况下使用,就是做一个代理服务,被测系统访问代理服务,代理服务通过流量来确认是否是测试流量,测试流量走mock或者线下的依赖或者模块,正式的就访问真实的依赖或者模块。除此之外,系统中可以标记测试流量写入的数据,在验证完后再清除。

    整体上看流量标注或者特定数据的方式,需要对系统代码或者线上环境进行改造,成本相对来说比较大。模拟线上环境相对来说更好实现,但也要投入一定的人力和机器资源。所以是不是要做,要看系统是否是一定需要线上验证,如果因为缺少线上验证而导致的问题比较多已经成为业务的痛点,可以考虑使用上边的方法。

 六、综述

    上面讨论了测试设计的几个面,主要是由之前的工作经历里总结而来,并不能覆盖所有的情况,只是给大家一些启示。现实中的项目可能有各种各样的特殊性,QA需要详细的了解整个系统以及上下游交互,才能制定出最合理的测试方案,尽量避免把问题带到线上。

    另外,上面虽然讨论了5个方面,但并不是所有的项目都适用,在实际项目中,往往需要结合对系统的了解和项目整体排期的时间要求,来做合理的取舍,在一定效率下尽可能的提升项目质量。

你可能感兴趣的:(测试开发技术(一)—— 测试设计)