在敏捷项目的快速迭代中,QA要负责和推动多个质量保障活动比如需求分析、过程改进、风险管理、自动化测试开发维护和故事卡验收测试等;其中留给故事卡验收测试的时间是有限甚至是紧迫的,但是质量要求却一点也不能放松。
那么如何在敏捷快速迭代交付压力下快速地进行故事卡验收测试?由于故事卡验收测试中的测试设计是最花精力和时间的,所以这个问题又可以进一步分解为下面两个子问题:
- 如何快速的进行测试设计?
- 如何设计出覆盖率高的测试用例?
我们在分析解答这两个问题之前,要强调一下进行测试设计的前提:
- 对产品(待测系统)业务逻辑的充分了解 - 可以帮助QA从用户角度进行场景设计以及避免遗漏任何改动相关的功能
- 产品功能
- 产品平台
- 产品接口
- 产品数据流
- 产品操作
- 产品用户体验
- 对产品(待测系统)实现技术的充分了解 - 可以帮助QA了解实现细节来减少测试范围
- 产品类型
- WEB
- Mobile
- 桌面软件
- 产品技术架构
- 产品技术栈
如果上面的前提都不满足的话,是很难设计出好的测试用例的。
现在我们来仔细分析上面提出的两个问题
问题1: 如何快速的进行测试设计?
舍弃传统测试设计方法,避免过度设计,采用思维导图等方式进行粗粒度的快速设计
在传统的测试设计方法中,QA需要依据需求文档,进行对应功能的详细的用例设计数据设计;然后把测试用例录入到电子表格或是一些测试用例管理工具中比如Testlink,QC等。类似这样的工具都要求测试用例具有非常详细的信息比如测试环境、测试步骤、测试数据测试期待结果,于是QA会花大量的时间在测试用例的设计和编写录入上。
在敏捷项目中,我们提倡采用探索式测试来进行手工验收测试。探索式测试是一种基于反馈的,边设计边执行的测试方法,不会要求详细的脚本化的测试用例,只需要选定某种特殊的测试方法在产品上进行深入的探索。所以,QA们不会使用具体的测试用例管理工具去编写详细的测试用例,而是使用简单的工具(例如思维导图)记录简单的测试想法/测试功能点,在实际的测试执行过程中,会针对某一个测试想法进行探索式测试。 这些测试想法/测试功能点只需要描述清楚测试的功能点是什么,基本的用户场景和数据是什么即可,通常来说一句话就能覆盖。此外,使用Gherkin语言描述(前提条件"GIVEN",发生什么操作"WHEN"和结果"THEN")也是一种方法。
比如对于To Do List这样的一个应用,QA不需要去设计编写繁琐的test cases/steps,只需要写出类似下面的测试想法
- 测试想法1: 加入一个task,然后完成这个task
- 测试想法2: 加入多个tasks,然后一次性清空全部tasks
- 测试想法3: 加入多个tasks,然后删除某几个tasks
- 测试想法4: 使用filter过滤tasks list
在实际测试执行过程中在使用探索式测试(漫游测试),比如拿上面测试想法来举例
- 测试想法1
- 超模漫游: 测试系统界面
- 反叛漫游: 系统会不会接受错误的task描述,比如为空的task,全是空格的task
- 沙发土豆漫游: 有没有默认值?placeholder?
- 测试想法2
- 找茬漫游: 能不能清空后再次在无task状态下清空
- 测试想法3
- 快递漫游: 删除后tasks只是从前端删除还是从后端删除?涉及数据库不
- 测试想法4
- 反叛漫游: 当没有适合条件的task的时候,filter之后的结果是什么,界面如何显示
可见采用测试想法思维导图和探索式测试将会有效的减少测试设计和执行时间。当然测试想法的记录形式不局限于思维导图,使用简单的word文档进行文本描述,使用excel文档进行表格描述都是可行的,只要符合"KISS"原则即可。具体怎么设计测试想法和应用探索式测试,会在稍后提到。
"Shoulder Check"可以帮助QA确认代码改动影响范围从而变动测试范围
在敏捷项目中,当故事卡需要从开发状态转入测试状态时,开发和测试会在一起进行"Shoulder Check"。这个活动会让开发和测试一起“玩”一下刚开发完的新功能(或是bug fix)。开发会给QA展示这个故事卡所有的代码改动和通过验收条件来展示最终效果,与此同时QA也会提出自己的任何疑问。通过回顾代码改动,QA可以评估和与开发确认代码的影响范围从而变动测试的范围,一般来讲,基本都能够减少测试范围从而避免没必要的手工回归测试。
问题2: 如何设计出覆盖率高的测试用例?
由于现在产品业务逻辑日益复杂,迭代交付速度日益加快,按照规格需求来写详细的测试用例,并加以等价类、边界值、因果图和判定表等测试用例设计方法已经不能满足当前对测试“快又准”要求。快速地进行粗粒度的测试设计并不等于忽略掉很多测试场景和数据,QA需要的是一种测试设计思路来指导具有高覆盖率的测试用例设计。
下面主要介绍我在日常工作中如何进行故事卡验收测试的设计和执行。在故事卡已经满足提测标准的前提下,整个测试设计和执行一共分为五轮:
- 使用RST(Rapid Software Testing)进行基于风险或缺陷模型的测试,目的是快速发现一些典型缺陷
- 使用HTSM中的Test Techniques和软件属性分类创建测试,目的是归纳出适用于故事卡的测试维度和覆盖到最基本的测试点
- 使用各类测试建模方法创建指导测试设计的模型,目的是通过建立好的产品模型给每个测试维度加上丰富的测试想法
- 使用探索式测试之漫游测试来扩展每个测试想法,目的也是给每个测试维度加上丰富的测试想法,也有可能会增加新的测试维度
- 使用探索式测试执行各个测试想法,目的是在执行测试的同时扩展思路,创造更多的测试路径,也会基于系统执行结果的反馈,不断优化测试想法
接下来我们深入的探讨下每轮测试实现的方式
第一轮: 基于RST的测试设计和执行
快速测试RST(Rapid Software Testing)是技能和思维模式,通过一种快速,低投入,可行和可靠的方式来做更加有效的测试。具体做法是针对某些常见的风险或缺陷模型进行专项深度测试。RST能够帮助QA在短时间内发现一些特定类型的缺陷,这些错误可以是需求设计上的业务逻辑错误,也可以是平时测试中经常遇到的缺陷。这一轮也类似于传统测试用例方法中的“错误推测”方法,只不过不是基于经验和直觉,而是依靠的总结归纳的“缺陷模型”。
因为RST只是针对一些特定的软件缺陷进行,所以这一轮测试不会进行太多的测试设计也不要求QA具备丰富的产品知识。
典型的测试方法有
方法名 | 所针对风险 | 测试手段 |
---|---|---|
用户界面 | 软件界面易用性差,会让使用者疑惑 | 测试人员漫游用户界面,发现是否有任何令人疑惑、不快、烦躁的界面设计,发现是否有可改进之处 |
错误处理 | 软件的错误处理代码容易出错 | 测试人员尝试着触发软件的错误消息,然后反复执行导致错误消息的操作,以检查错误处理代码是否产生了资源泄露等问题。 |
快乐路径 | 软件在典型用户情景中失败 | 测试人员测试产品最简单、最直观、最典型的情景,完成一项或多项用户任务。在此过程中,检查其表现是否符合用户和产品团队对它的期望,而不会让用户感到疑惑、恼怒、挫折等负面情绪 |
挖墙脚 | 软件不能正确处理一些异常情况 | 测试人员启动一项软件操作,然后破坏该操作所依赖的资源,例如删除它要访问的文件、关闭它将访问的网络服务、启动另一个程序去锁住它要修改的数据库表格等。软件应该妥善地处理这些异常,合理地报告所遭遇的问题,不导致严重的故障 |
狗刨 | 当某些操作被反复执行时,软件可能出错 | 测试人员将一组操作重复多次,用并发的流程、嵌套的结构去考验软件。例如,文本编辑软件支持嵌套文本框,于是测试人员就不断在文本框加入新文本框,以增加嵌套层次。当文本框嵌套层次达到上限时,操作这组文本框有可能发现隐藏的缺陷 |
功能交互 | 不同的功能可能由不同的程序员(或同一个程序员在不同时间)编写,它们的逻辑可能不一致 | 测试人员发现相互调用或共享数据的一组功能,然后用夸张的数据或操作来压迫它们,以暴露交互中存在的问题 |
QA在这一轮中通过已有的产品缺陷模型和寻找故事卡改动可能会引起的缺陷来进行测试,这样会快速的找到一些典型的缺陷。如果还没有产品缺陷模型,那就赶快归纳总结出产品发生过的缺陷和发现手段。
第二轮: 基于HTSM和软件属性分类的测试设计
HTSM中提供了九种测试技术,这些测试技术用来启发创建测试。
下面列出了这九种通用的测试技术。“通用的测试技术”是指技术是简单明了的且可以脱离复杂的上下文普遍适用的。很多特殊的技术都可以基于下面九种测试技术中一种或是多种。通过组合通用技术和本模型中其他的元素,我们能够得到很多特殊的测试技术。
-
功能测试 Function Testing
- 描述:测试软件的能力
- 典型思路
- 辨识产品能做的事情
- 决定你怎么知道产品能工作
- 一次只测试一个功能
- 测试每个功能只做了它应该做的事情而没有做它不应该做的事情
-
域测试 Domain Testing
- 描述: 专注于测试软件所处理的数据
- 典型思路
- 找到产品处理的所有数据。看输出也看输入
- 决定哪些特殊的数据需要测试。考虑边界值、典型值、无效值和最佳代表数据
- 考虑数据的组合
- 数据初始化
- 数据默认值
- 数据完整性,在不同模块之间的赋值和调用
-
压力测试 Stress Testing
- 描述:用极限行为和数据压迫软件
- 典型思路
- 寻找极易遭受挑战性数据和被限制的资源破坏的子系统或是功能
- 选择或创建有挑战性的数据或者资源限制条件进行测试。比如庞大或是复杂的数据结构,高负荷,持久测试,大规模测试用例和低内存条件
-
流测试 Flow Testing
- 描述: 测试软件的操作顺序
- 典型思路
- 测试多个活动串联以后端到端的流程。比如在状态模型中开展漫游测试
- 不要在活动中重设系统
- 改变时间线和顺序,试试并发
-
情景测试 Scenario Testing
- 描述: 用有说服力的场景来测试软件
- 典型思路
- 开始时思考关于产品的一切
- 设计测试来覆盖与产品有意义的和复杂的互动
- 一个好的场景测试是一个引人注目的故事,这个故事涉及谁做了什么影响产品的事情
-
声明测试 Claims Testing
- 描述: 测试所有产品资料 Challenge every claim
- 典型思路
- 调查所有的声明,澄清所有的声明
- 鉴别所有关于产品的参考资料
- 测试关于产品声明的精准性
-
用户测试 User Testing
- 描述:从用户角度测试 Involve the users
- 典型思路
- 识别用户的角色分类
- 识别每一类的用户分别会做什么事情,怎么做以及带来的用户价值是什么
- 获取真实的用户数据来进行测试
- 否则,系统性地模拟一个用户(这里有一个坑,就是你很容易自以为你就是真实的用户,而不是你并不是)
- 强有力的用户测试通常都会涉及多个不同类别的用户和不同的角色,并不是某一个
-
风险测试 Risk Testing
- 描述:猜想一个问题,然后去尝试发现它 Imagine a problem, then look for it
- 典型思路
- 这个产品可能会有什么样的问题
- 哪些问题最有严重或是最有可能性发生?先聚焦在这些问题
- 如果这些问题有可能发生,应该怎么去发现他们?
- 列出一个包含一些有趣问题的列表,然后设计测试去揭露他们
- 这个测试能帮助咨询专家,设计文档,历史缺陷报告或者启发风险
-
自动化检查 Automatic Checking
- 描述:自动检测大量不同的结果 Check a million different facts
- 典型思路
- 寻求或开发工具来做大量操作和检查大量结果
- 考虑能部分自动化测试覆盖率的工具
- 考虑能部分自动化测试先知的工具
- 考虑能够自动化感知变更的检测器
- 考虑能够自动化产生数据的创造器
- 考虑能够帮助人工测试的工具
此外我们也可以从下面软件属性分类来思考我们的测试用例设计
- 结构 --> 自动化检查 Automatic Checking
- 代码路径
- 功能 --> 功能测试 Function Testing
- 产品功能正常
- 产品异常处理
- 产品符合需求
- 后台功能正常
- 业务价值 --> 情景测试 Scenario Testing, 用户测试 User Testing
- 给客户带来的价值
- 依赖方
- 影响其他系统
- 平台 - 执行环境
- 测试产品依赖的环境
- 浏览器
- OS
- 不同配置项
- 网络
- 硬件资源使用情况
- 测试产品依赖的环境
- 数据 --> 域测试 Domain Testing
- 测试不同的数据类型
- 有效无效
- 大规模
- 输入输出
- 测试不同的数据类型
- 接口 --> 情景测试 Scenario Testing, 用户测试 User Testing
- 交互方式
- 人工界面
- 自动程序
- 交互方式
- 状态 --> 流测试 Flow Testing
- 不同状态
- 持久
- 一致
- 不同状态
可见HTSM还是覆盖了大部分上面的软件属性,需要注意的是"平台"所对应的兼容性测试并没有在HTSM中列出来,而QA需要测试软件在不同执行环境下的表现。
QA在这一轮需要探索和决定上面测试技术中哪些适用于当前的故事卡(产品功能),把适合的测试技术与故事卡的变动联系起来,确定了针对本次改动的测试范围和基本测试点。比如说"Domain Testing"域测试是专注于测试数据的测试技术,基本适用于每一个故事卡。当确定域测试适用之后,QA就会产生下面的测试想法:
- 该变动影响和涉及的测试数据有哪些?
- 数据作为输入变量
- 数据作为输出变量
- 测试数据有什么类型?
- 有哪些无效的数据?如何被系统识别和处理?
- 有哪些有效的数据?不同的有效数据类型如何被系统接收和处理?
- 最重要的测试数据是哪些?考虑边界值、典型值、无效值和最佳代表数据
- 测试数据如何产生?
- 用户产生数据的方式有有哪些?
- 测试数据如何被系统处理?
- 大规模的数据处理
- 同一数据在不同模块之间的处理
- 能否被存储成功
- 测试数据会在哪些地方以什么方式呈现给用户?
- 测试数据有哪些特点
- 完整性 - 数据在被不同功能或模块容纳处理后依然完整
- 唯一性 - 数据是否在系统里唯一,不能有重复
- 一致性 - 单一数据在系统里显示一致
- 冲突性 - 不同数据之间是否冲突
上面提到这九种技术是非常通用的,如果发现故事卡有需求变动不能被这九种技术覆盖掉,那么QA需要考虑自己“创造”一种测试技术来覆盖需求。此轮测试相比于RST,这一轮测试会涉及更多业务领域知识,最基本的业务功能都会在此轮测试中被覆盖到。
基于测试建模的测试设计
测试建模是以指导测试设计为目的建立产品模型,此产品模型就是测试建模的产出。这个产品模型包含着大量测试需要关注的信息。
QA常使用的测试建模手段有哪些呢?
1.组合测试
- 组合测试(combinatorial testing)是一种测试用例生成方法。测试人员将被测试对象抽象成一个受到多个变量影响的系统,其中每个变量的取值是离散且有限的。
- 两因素组合测试(pairwise combinatorial testing,配对测试,全对偶测试) 生成的测试集可以覆盖任意两个变量的所有取值组合。在理论上,该用例集可以暴露所有的两个变量共同作用而引发的缺陷
- 多因素组合测试(n-way combinatorial testing) 生成的测试集可以覆盖任意n个变量的所有取值组合。在理论上,该测试用例集可以发现所有由n个因素共同作用引发的缺陷
- 常用工具:PICT生成满足特定组合覆盖标准的组合测试用例集
- 更多工具集
2.输入输出模型/IO模型
- 输入输出模型是最基本的测试模型,这个模型列举了被测对象所有的输入变量和输出变量,然后定义了输入输出的关系。这个模型经常被用来设计数据和流程相关的测试。
3.状态机模型
- 分析识别出被测对象所有的状态以及状态之间进行变迁的触发事件,这样我们可以得到一个状态图
- 通过分析状态图,QA可以设计测试用例覆盖所有状态、所有状态变迁和所有触发事件
- 也可以把状态图转变为状态表
4.功能列表
- 用列表的方式列出产品的主要功能和子功能
QA在这一轮测试中需要观察上轮中得到的测试想法可否使用测试建模技术来细化;如果可以细化,那QA可以得到更多的测试想法和更加精确的测试数据。
基于探索式测试之漫游测试的测试设计
探索式测试可以用于帮我们在测试设计中开发出测试用例,它也可以帮助我们发现在规范说明书中可能漏掉的用户场景,还可以组织测试人员的测试思路。探索式测试之漫游测试是在特定主题指导下对产品进行探索的一组测试方法,这里列出一些最常见的方法。因为这一轮测试是基于上几轮测试的结果,所以我们使用HTSM的九种技术来展示漫游测试方法可以发挥巨大作用的地方。
-
功能测试 Function Testing
- 卖点漫游:测试人员发现并测试软件的卖点,这通常是销售人员和广告资料重点强调的特性。该漫游与之前介绍的价值漫游都有助于分析软件的核心价值是否存在风险
- 配角漫游: 测试人员重点测试软件的非主要功能。例如,对话框上有一条指向帮助文档的链接,很少有用户会注意到它。测试人员则需要点击该链接,以检查它指向正确的文档。该漫游有助于完整地测试软件的每个功能
- 超模漫游: 测试人员重点测试软件界面,检查界面是否美观、控件是否正确、动画是否流畅、色彩是否协调、刷新是否及时、字体是否优雅等
- 破坏者漫游:测试人员实施故障注入和错误容忍方面的测试。他故意破坏或移除软件操作需要的资源,然后强制软件执行注定导致失败的操作。该漫游将测试软件能否合理地处理(不可避免的)失败,且不会导致更严重的后果(如用户数据丢失)
-
域测试 Domain Testing
- 快递漫游:测试人员跟随一组数据走遍软件的功能。例如,测试PowerPoint图片时,测试人员跟随一组图片,测试图片导入、图片编辑、图文混排、图片导出、幻灯片打印等功能,并时刻检查图片操作的正确性
- 沙发土豆漫游:测试人员尽可能不提供或修改数据,这意味着接受软件提供的默认值、保持表单字段为空、或只提交最少的数据。该漫游检查软件可以处理它提供的默认值、空值和可选字段
- 收藏家漫游: 测试人员通过测试去收集软件的输出,收集得越多越好。例如,测试PowerPoint图片时,测试人员要收集各种图片导出的结果,以覆盖图片格式、图片色彩、图片效果、图片尺寸等因素。该漫游有助于周密地覆盖软件的计算结果
-
流测试 Flow Testing
- 地标漫游: 测试人员选择一组相关的功能,依次测试,直到测试了所有功能。该漫游与功能漫游相似,都可以探索并学习软件的功能,用一组地标(功能列表的主干)产生详细的地图(功能列表的分支)
- 停车场漫游: 该漫游探测软件的’地形’, 其主要目标是发现所有功能的入口(面向覆盖)和有可能发生的问题(面向风险),次要目标是确定具体的漫游方法可以应用的地方,幸运目标是发现一些极端严重的缺陷
- 出租车漫游: 测试人员发现并测试触发某一功能的所有途径,或完成某项任务的所有方式。该漫游有助于完整地考虑并测试一个功能或情景
- 歧路漫游:该漫游是一种特殊的反叛漫游,它要求测试人员以错误的方式或顺序来操作软件。例如,测试人员故意调换工作流的步骤,故意利用未经初始化的数据等
-
情景测试 Scenario Testing
- 傲慢美佬漫游:测试人员用一些不合“正常”逻辑的情景来测试软件。例如,测试在线交易网站,提交订单并支付后,又取消订单并要求退款。又例如,提交订单后,又申请去更改送货地点和送货方式。该漫游有助于发现软件在不常见情景中所暴露的错误
- 混票漫游:该漫游针对情景测试,以引入更多的测试变化。它要求测试人员跟随一个测试情景访问某个功能,然后再利用另一个测试情景去测试其他功能。这有助于混合测试多个情景,发现由功能交互引发的问题
-
风险测试 Risk Testing
- 找茬漫游: 测试人员在测试软件时,以找茬的心态去挑战软件。他提出各种问题去质疑软件,例如:“如果我这么做,会如何?如果我偏不这么做,又如何?如果我不想这么做,有什么替代方案?” 该漫游有助于发现程序员设计的不足和软件逻辑的漏洞
- 风险识别漫游: 风险识别漫游产生软件的风险列表。测试人员可以分析软件的各个部分,想象它可能遭遇的失败,以列出一组软件面临的风险。测试人员还可以漫游产品的功能并沿路思考:“此外, 软件可能发生什么错误?它可能遇到什么异常情况?”以获得一组潜在风险
- 极限值漫游:极限值漫游是一种特殊的风险识别漫游。它通过输入极限值或制造软件的极限状态来发现软件的错误。常见的极限值包括零、最小值、最大值、空值、NULL、负值(当软件期望用户输入正数时)、不正确的数据格式等
- 知识分子漫游: 测试人员运用业务和技术知识向软件提出极具挑战的问题,例如:“软件能处理的最大流量是多少? 哪些操作会索取最多的内存?” 成功运用该漫游的前提是测试人员深刻地理解业务、设计和实现,并可以设计出有挑战性的测试用例
QA在这一轮测试中需要利用漫游测试方法带来的启发在每个测试分类中创建更多的测试点和测试数据, 这一轮测试设计中,更多的异常测试用例会被挖掘。测试设计也基本完成了。
基于探索式测试的测试执行
接下来我们需要“按部就班”的执行设计好的测试点,不会像执行固定的脚本一样去执行测试用例,而是还会在执行的过程加入一些变化。
在执行某个测试点时,我们可以
- 根据实时测试结果反馈
- 发现是否遗漏了一些需求
- 挖掘新的测试数据
- 决定是否创建新的测试点或是删除无效测试点
- 变动某个测试步骤来增加场景的多样性
- 在遇到有业务逻辑分歧的时候,可以尝试先往不同路径测试,最终再回到主路径
所以整个测试执行是基于测试结果反馈的,QA既测试了之前设计好的用例,又在测试扩展测试了其它没有提前设计的用例。
总结
通过改变测试设计方法和精准定位代码变动影响范围,QA可以减少大量测试设计和执行时间。通过五轮不同目的的测试,QA考虑到了一次故事卡变动影响的方方面面,每一轮测试有其独特的使命,提高了测试用例覆盖率,避免了测试冗余。只有把所有可行的测试方法都组合起来使用,才能设计出高覆盖率的测试用例。
参考资料
- 软件测试实战
- 测试架构师修炼之道
- HTSM
- RST
- ET