如何编写测试用例
流程步骤
先用一张简单的流程图说明下写用例的基本步骤,其中需要注意的是,并不是用例写完就不变了,它跟代码一样,要根据实际运行的结果进行维护修改,确保下次执行时可以更准确更高效。
一、阅读文档
一份测试用例不是凭空产生的,最基本的依据就是需求设计文档。如果没有需求文档,就需要自己先去弄清楚需求内容和使用方式,然后尽可能详细的罗列出来,形成需求清单。阅读文档的目的,除了确认需求的内容和边界外,还可以将一些不明白的地方跟相关人员核对清楚。一份合格的需求文档,应该包含如下格式和内容:
『设计目的』:用尽可能精简的语句描述需求是什么,以及期望达到怎样的效果。如果有参照对象,就附加上参考的对象是谁,参考了多少内容。先让大家可以建立起一个认知基础,之后可以更快速地理解细节内容。
『流程模块』:主要包含两个部分,一方面是整体概括描述:如何开始,如何结束,中间经历怎样的过程,建议用流程图。另一方面是流程图中每个节点模块的具体说明,比如有怎样的限制条件,过程如何处理,向下个环节输出怎样的结果等。这一部分主要是帮助大家建立对需求的具体的实现过程,尤其对于服务端程序来说十分重要。好的流程图可以直接给程序同学提供代码结构上的参照,不必重新组织逻辑关系。
『交互操作』:有的时候指的是『表现效果』。前面的『流程模块』其实是站在上帝视角,从整体去描述整个需求构成的,但用户体验角度上来说,看到的每个画面,每个操作是怎样的,是否清晰合理,能够有效引导用户操作,也是需要精心设计的。同时,也是为了让客户端程序和美术同学更加详细具体的知道设计师想要的效果是怎样的,避免后期反复的修改调整。当然,很多开发团队为追求更高的设计专业性,将这种工作单独划分了出来,称之为交互设计师,产出的主要有UE设计文档和Page-Flow图。
『数值奖励』:任何一个需求的设计,都一定会包含奖励和数值的内容,哪怕这些内容占的比例再小。因为奖励起到着重要的承接作用,它直接鼓励和引导玩家重复地进行过程操作,吸引玩家不断深入。甚至有一些功能需求在设计初期,就要考虑到它所能产出的奖励内容,调整过程的复杂度。而数值则是影响过程体验的重要指标之一,以最常见的战斗来说,数值平衡是最难做到的,而一旦数值不平衡了,会严重影响体验的公平性,增加玩家的挫败感,最终也就不会再有人玩了。当然,奖励数值如果也交给专门的策划去进行设计,并从整体上把握所有数值之间的流转过程,平衡关系的话,这样的策划一般称之为数值策划。
『关联系统』:主要描述当前的功能需求,对其他功能需求的影响,以及将来可能的扩展内容。很多策划文档很容易漏掉这一些,其实从中也可以看出设计师对需求的考虑是否足够全面。而关联系统的内容,也可以有效地指导测试同学去发现功能需求之间相互影响的测试点,从整体结构上进一步保障产品质量。
二、测试分析
首先分析需求,简单来说就是『关键词提取』。在阅读需求文档过程中,将一些重要的流程,模块名称摘录出来,用Xmind记录好,组织好主从关系。每一个关键词至少包含一个或多个测试点,而通过关键词的主从关系可以预见到应该先测什么,再测什么的执行步骤。
提取和组织关键词之后,还要针对这些关键词去思考如何测试,也就是测试点。举个简单的例子,最常见功能有参与的『等级限制』,那么两个基本测试点就是:『不满足等级时能否参与』和『满足等级时能否参与』。完成测试点的细化后,形成Xmind思维导图(如下)的过程,一般称之为测试分析,而这份思维导图还不能称之为『测试用例』,只能算作草稿。如下图:
三、编写用例
测试用例是用于指导实际的测试行为的,所以要有着清晰的格式(前置条件,执行步骤和预期结果)和明确的描述语句,即便不是写这份用例的人也可以对照执行,完成操作。完成后的测试用例大致如下:
首先,解释下测试用例的核心三要素:『前置条件』、『执行步骤』和『预期结果』;分别对应着:在怎样的情境下进行测试?采取怎样的测试行为?预期会产生什么样的结果?
然后,为了便于执行记录,还有作为补充说明的『备注』,还有标记『测试结果』是否通过,以及过程中遇到问题的『执行备注』。
最后,为了便于用例的维护管理,以及不易遗漏测试点,所以还会有结构性分解的『测试目标』,注明用例对应的功能名称,对应的需求文档,开发人员,用例编写人及编写时间等。
需要特别说明的是第一列的『分级』,常见的用例一般第一列用ID标识,这样就可以直接说是第几条用例,这个可根据自己的需要进行添加。而我使用分级的是为了两个好处:
将测试用例标出优先级,「1」表示最基本最重要的测试点,是保证绝对不能出错的部分;「2」表示的是主流程以外,比较特殊的异常情况下进行的测试,可能潜藏着意想不到的问题;「3」表示一些额外、存在不确定性的内容,需求文档没有写,也没有绝对的对错要求,只为探索一下是否可能存在问题。
可以根据测试计划,筛选出指定的用例进行执行,而不必每次测试都执行所有的用例。例如在进行单服验收和发版Checklist的时候,只需要执行「1」级用例,在进行集成测试,就要执行「1」「2」「3」级所有用例才能确保测试全面,但如果时间有限,或者操作太过复杂,也可以先不执行「3」级用例的测试。
四、测试执行
用例写好后,至少要经过一轮实际的测试执行,才能确认用例是真正写完了,否则一份用例写出来之后不能用,等于白写。随着设计需求的变更,bug的修复,用例的内容也都要随之一起调整。
上面这些步骤,可能会让人觉得这是很典型的课本理论,实际工作过程中哪里需要这么繁琐,或者等熟练之后,就不需要按照这些步骤进行了。简单写点测试用例,或者干脆测试用例也不写,直接就开始测试也能保障功能质量。这种想法不能说错,我也这么干过,如果你的测试任务只需要做一遍,而且十分简单,这样做我觉得无可厚非。但如果你的测试对象很复杂,而且需要经过多次测试,写一份测试用例就十分必要了,而且每次测试后还需要修正完善用例内容。一份好的测试用例可以帮助你查缺补漏,可以几何式地提升第二、第三次测试的效率。还有很重要的一点就是,如果你还负责管理一个测试团队,大家都不写测试用例只知道埋头干活的话,你会发现产品总是出问题,甚至出重复同样的问题,而你根本不知道原因出在哪里,因为大家都在辛苦地忙碌着,只不过所有人测试的方法和内容都只存在每个人的脑子里,然后看每个人的心情去执行。这样的管理方式,只会让人心力交瘁,疲于应对。
写用例的经验分享
● 先正常再异常
很多测试新人,拿到测试需求,按顺序跑一遍觉得这个就叫测试了,所以很多人误以为测试很简单。按顺序跑一遍,只能确保最基本的正常流程是可用的,确认正常流程可用后,我们再去尝试一些异常的情况:比如输入错误的数据,中断流程后能否恢复。
不过进行异常的破坏性测试,最好采用的方法都是较为常见合理的,比如打错字,点错按钮,断网,关闭客户端之类的,这样的问题程序会比较愿意处理。
● 先整体再局部
功能测试常用的测试方法都属于“黑盒测试”,这是因为测试时我们是看不到内部的逻辑过程是怎样处理的。但也正是因为如此,我们才可以不局限于实现的方式,靠自己的经验、想象去猜测和摸索,这其实才是测试行为最宝贵的地方。我们先对功能整体的内容进行梳理,先不必细化,只需要知道它从哪开始,到哪里结束。当整体上看起来是完好的之后,我们来拆解它的步骤,观察它是如何开始的,开始时需要满足什么条件;还有如何结束的,结束时产生什么内容;最后再记录过程发生了什么。当能够清晰地知道开始和结束的边界后,就可以将这两个模块从整体上剥离开来,然后把过程当作一个新的功能,再去重新拆解它的开始和结束,这样一层层深入下去,慢慢就可以刻画出它的实现过程了。
然后再拿你探索出来的去跟开发人员进行核对,如果有很多一致的地方,会感觉很有成就,如果有很多不同的地方,就要思考为什么不同,有没有可能存在没想到的问题。
● 先前端再后端
当你拆解出了功能流程的时候,就可以思考下,这个流程中,哪些是前端做的处理,哪些是后端做的处理?这里的前端后端,指的是程序开发中常分的客户端和服务端。客户端主要负责表现效果,后端进行实际的数据计算。所以但凡影响显示的,比如打开一个界面,显示一段文字,基本都是前端的问题;而涉及到具体数据变化的,比如购买物品时扣钱,一般都是后端处理。
一般来说,我们写的测试用例,主要的测试点都是围绕后端逻辑的,因为前端的问题在测试过程中比较容易被发现,而后端的问题隐蔽性强,表现效果多样;当然主要也是因为计算逻辑大多集中在后端,数据的重要性更高,出错的影响性更大。所以很多条件判断一定要放在后端进行,比如买物品时判断钱够不够。如果有技术条件,能够绕过客户端对服务端直接发送数据协议的话,也是可以尝试的,这部分属于安全性测试,后面会详细讲到。
但也不是说前端的问题都不大,像引发客户端崩溃、卡死的问题,一旦出现了,游戏也就玩不了了,这也是很致命的问题,所以客户端测试时一定要多尝试异常情况,比如空数据的显示,超过上限的显示,同时打开两个互斥的界面等等。
● 先独立再关联
游戏功能一般都不会独立存在的,都会与其他功能相互关联影响的。考虑到测试成本,不可能每测一个功能的修改,就将所有内容全部过一遍。从设计和开发的角度来说,也应极力避免功能之间的高耦合性,如果总是“牵一发而动全身”,产品可能永远都做不完,问题永远都改不完。所以,在测试的时候,我们先尽量收缩测试范围,减少不必要的工作量,确认功能本身的正确性和稳定性之后,再考虑与其他功能之间的关联影响。一般来说,关联性主要分为四种(其中数值和输入输出关联,属于弱关联,测试简单,问题明显;而流程和情景关联属于强关联,容易形成系统性的影响,问题出现的原因一般不那么明显):
数值关联:例如装备系统里『装备强化』会在基础数值上再按百分比增加数值,而『装备洗练』则是会改变基础数值。所以在测试时,就要尝试下先强化再洗练和先洗练再强化这两种顺序,最终的计算结果是否都正确。
输入输出关联:也就是某个功能的产出是另一个功能的消耗。正常来说,这两个功能单独测试,并且确认各自的产出、消耗是否正确就可以了,但游戏开发过程中需求时长变更,产出消耗也经常进行调整,所以最好两个功能测试里都去留意下对方的产出消耗是否正常。不需要测试过程是怎样的,只要确保实际产出和消耗入口的内容、数量正确就可以了。
流程关联:最简单的流程关联就是完成某个任务才能开启某个功能了;比较复杂的,就是对游戏的历程的影响了。(游戏历程指的是游戏玩家,从新建角色开始,按照任务指引熟悉游戏内容,逐步上手并深入游戏玩法的成长过程。)功能少重复性强,容易令玩家厌烦;开启的功能太多又会过度分散玩家对核心内容的体验。
情景关联:或者叫状态关联,这种可以说是最容易忽略的关联关系了,因为不同的设计和开发人员自己都不知道自己的功能将在什么情境下被使用,很多奇葩的问题也由此产生。比如《剑网三》曾经有个副本boss,会给玩家加一个debuff,对周围人造成伤害。有玩家将其带出来后在和平地图可以对其他玩家造成伤害。有些功能设计本身就是要在不同情景下使用的,例如组队,所以组队本身的功能测试不复杂,复杂的是考虑它在各种功能中的处理方式。
新手写测试用例时最常见的问题
写的太粗略或太细致,把握不好度。这在新人中最容易出现,虽然我们写测试用例讲究的第一个原则就是对照设计文档,分析需求,但即便是这样一个相同的过程,根据不同人的性格都会有两种很极端的结果。有的会写的很粗略,基本上就是把文档里各个功能点当作测试点来写,然后测的时候也基本上就只是确认相符还是不相符;有的又会写的很细致,比如写到点击什么按钮,打开什么界面,看到什么图标。我自己刚开始的时候也是属于后者,而且这种情况我持续了一年多,至今觉得还有这方面的问题。写太粗了,根本没有测试分析,没有去挖掘测试点,测完一遍只能确保正常的流程是可以跑通的,但稍稍不一样的流程就潜藏着各种bug。写的太细又很累,效率低,后期维护成本也很高,要知道策划改需求常常是整个功能重做,或者是界面UI全换,那就意味着你的测试用例几乎也要重新写。而且,用例不是写的越详细越好,因为详细的可能只是界面操作上的内容,并不代表就能真正发掘到设计和实现上的潜藏问题。当然,没有绝对的用例标准能够解决这个问题,在这里只是想要提供一些方法心得来让大家掌握这个度。为什么上面介绍的流程要先用xmind整理需求点,其实这个就是在帮你理解设计,建立一个系统性认知,然后再逐个去思考需求点,考虑应该怎样去测,这就是测试分析的过程,做完这两步之后基本上就能覆盖到80%的测试点了,然后将测试点细化为可读性较好的表述文字,整理成模块表格,这就是测试用例了。什么叫可读性较好,就是一句话的表达意思,别人看了之后能够有着相同的理解,不要小看这一点,这个能力无论是写用例,还是提bug都很重要。写作能力,也就是文字表达思想的能力其实是一种通用能力,也是人的思维能力的体现。思路越清晰的人,表达的文字越简单易懂,同样那种看似华丽但却意义不明的大段大段的文字其实也是写作者本身思路并没有成体系化,想到什么就写什么,一边写一边联想,然后这样不断堆积下去的。
用例结构零散,或是太过顺畅。一般不建议每条用例单独一行,最好能从左往右,有个逐渐细分的过程。这样更利于建立清晰明确的测试目标,比如我这块就是为了测试限制条件,下一块就是为了测奖励。测试本身就是不断地在测试点进行横向挖掘,去探索各种可能性,所以每个节点上会停留较长时间。如果执行过程太过顺畅,完全按照功能流程不断地进行下一步操作,做事情就进入到一种自动驾驶的状态中,即便发现了一些问题或端倪,可能也会自动忽略它,除非这个问题阻断了你的流畅性。这个不是我在扯淡,而是我们大脑的天性如此,举个例子,我们看电视剧的时候大脑对信息的处理基本都是处于自动驾驶的状态,所以我们很少从电视剧中发现问题;而那些专业的影评或吐槽师,他们是带着明确的目标去看的,所以更容易发现问题。
写完就算完工了,执行过后就不管不问了。很多人写完测试用例,执行过一遍之后,就觉得自己对这个功能很熟悉了,下次不需要参考用例也知道该如何测试了。首先,写用例是训练思维的过程,而执行用例其实就是在验证用例设计思维是否正确好用,抛开用例其实就是只凭记忆、经验在做事情,简单重复的任务可以这么做,但如果一直习惯于这样的做事方式,就又让大脑进入了自动驾驶,从而忽略潜在的问题。其次,回顾写的旧用例其实也是自我改进的一次机会;即便到了现在,我看自己半年前写的测试用例,依然觉得有各种问题,出现这种情况的原因是你进步了,如果你看不到自己曾经做的有多差,你就不知道现在要如何改进以便将来更好。最后,是为了更好的团队合作。你的工作总会有人来接手,而且测试中还有一种测试方法叫『交叉测试』,意思是两个人互相交换用例,测试彼此的功能,以达到查缺补漏的目的。这里面不仅仅只是为了测试更完善,还有一定的管理目的,例如刺激团队成员之间的对比,融合彼此的思维方式和做事方法等等。如果你的用例写的不好或长久不维护,那么你的用例对其他人来说就是一个灾难,策划同学的文档,程序同学的代码也是如此。说到这里,我想再插一句,很多人以为文档简单,写代码难,所以判断测试高不高级,就看他会不会写代码,所以测试开发一定比功能测试高级?其实无论是文档还是代码,其体现的都是人的思维方式和做事方法,高低判断的标准不是它是哪种存在形式,而在于其发挥的作用和效率。绝大部分的情况下两者都需要,你可以选择做你更擅长的。