软件测试52讲
01 | 你真的懂测试吗?从“用户登录”测试谈起
在测试工作当中,设计测试用例方法包括很多种:等价类划分、边界值分析、错误推测、因果图、判定表驱动、正交试验设计、功能图、场景等。但是作为测试工程师,我们的目标是要保证系统在各种应用场景下的功能是符合设计要求的,所以我们就要考虑用例内容就需要更多、更全面。
当我们拿到“用户登录”的功能需求时,可以结合等价类划分和边界值分析方法来设计测试用例:
入门级别的测试用例:
- 输入已注册的用户名和正确的密码,验证是否登录成功;
- 输入已注册的用户名和不正确的密码,验证是否登录失败,并且提示信息正确;
- 输入未注册的用户名和任意密码,验证是否登录失败,并且提示信息正确;
- 用户名和密码两者都为空,验证是否登录失败,并且提示信息正确;
- 用户名和密码两者之一为空,验证是否登录失败,并且提示信息正确;
- 如果登录功能启用了验证码功能,在用户名和密码正确的前提下,输入正确的验证码,验证是否登录成功;
- 如果登录功能启用了验证码功能,在用户名和密码正确的前提下,输入错误的验证码,验证是否登录失败,并且提示信息正确。
有了些许经验的会增加测试点的用例:
- 用户名和密码是否大小写敏感;
- 页面上的密码框是否加密显示;
- 后台系统创建的用户第一次登录成功时,是否提示修改密码;
- 忘记用户名和忘记密码的功能是否可用;
- 前端页面是否根据设计要求限制用户名和密码长度;
- 如果登录功能需要验证码,点击验证码图片是否可以更换验证码,更换后的验证码是否可用;
- 刷新页面是否会刷新验证码;
- 如果验证码具有时效性,需要分别验证时效内和时效外验证码的有效性;
- 用户登录成功但是会话超时后,继续操作是否会重定向到用户登录界面;
- 不同级别的用户,比如管理员用户和普通用户,登录系统后的权限是否正确;
- 页面默认焦点是否定位在用户名的输入框中;
- 快捷键Tab和Enter等,是否可以正常使用。
其实上述都是根据明显的功能上的需求来设计用例的,但在软件测试的维度来看,除了这些显性的功能需求,非功能性需求也很重要,它涉及到安全性、性能及兼容性三大方面,这些容易被我们遗漏忽视的,往往也是决定软件质量的关键因素。
安全性测试用例包括:
- 用户密码后台存储是否加密;
- 用户密码在网络传输过程中是否加密;
- 密码是否具有有效期,密码有效期到期后,是否提示需要修改密码;
- 不登录的情况下,在浏览器中直接输入登录后的URL地址,验证是否会重新定向到用户登录界面;
- 密码输入框是否不支持复制和粘贴;(补充:右键方式和热键方式)
- 密码输入框内输入的密码是否都可以在页面源码模式下被查看;
- 用户名和密码的输入框中分别输入典型的“SQL注入攻击”字符串,验证系统的返回页面;
- 用户名和密码的输入框中分别输入典型的“XSS跨站脚本攻击”字符串,验证系统行为是否被篡改;
- 连续多次登录失败情况下,系统上是否会阻止后续的尝试以应对暴力破解;
- 同一用户在同一终端的多种浏览器上登录,验证登录功能的互斥性是否符合设计预期;
- 同一用户先后在多台终端的浏览器上登录,验证登录是否具有互斥性。
性能压力测试用例包括:
- 单用户登录的响应时间是否小于3秒;
- 单用户登录时,后台请求数量是否过多;
- 高并发场景下用户登录的响应时间是否小于5秒;
- 高并发场景下服务端的监控指标是否符合预期;
- 高集合点并发场景下,是否存在资源死锁和不合理的资源等待;
- 长时间大量用户连续登录和登出,服务器端是否存在内存泄漏。
兼容性测试用例包括:
- 不同浏览器下,验证登录页面的显示以及功能正确性;
- 相同浏览器的不同版本下,验证登录页面的显示以及功能正确性;
- 不同移动设备终端的不同浏览器下,验证登录页面的显示以及功能正确性;
- 不同分辨率的界面下,验证登录页面的显示以及功能正确性。
由于在整个项目周期迭代中,测试因受限于时间成本与经济成本,是无法去穷尽测试所有满足前提条件的数据组合的,而是采用基于风险较大的驱动模式,侧重选择测试范围和设计测试用例,以寻求缺陷风险和研发成本之间的平衡。
其他补充:
- 网络延迟或者弱网或者切换网络或者断网时是否正常登录;
- 是否支持第三方登录;
- 是否可记住密码,记住的密码保存是否加密,记住密码是否有有效期,过期之后是否会清空密码;
- 密码强弱性校验,数据库设计和数据操作时是否合理;
- 用户登录过程中log是否对个人信息及密码明文打印;
- 登录用户限制:比如同时支持10个用户登录,同时9个或者11个用户登录是否正常或者提示信息正确;
- 未激活的用户登录;
- 被停用的用户登录;
- 涉及资产风险的,对登录设备和地区检测;
- 为空和输入空字符串时的校验;
- 使用中文键盘输入字母时和使用英文键盘输入字母时传给后端的字符串长度是否一致;(补充:全角与半角符号的区分,软键盘的输入)
- 登录成功后的session时效设置;
- 密码一栏是否需要设置明暗码切换按钮;
- 输入栏是否设置快速删除按钮;
- 是否用到缓存;
- 用户名和密码是否对空格敏感;
- 更改密码后是否还能用之前的密码登录;
- 一个用户是否具备多种登录方式(用户名,手机号,邮箱等);
- 第三方登录修改密码的影响(解绑后是否能正常登录和登出);
- 是否可以使用登录的API发送登录请求,并绕开验证码校验;
- 是否可以用抓包工具抓到的请求包直接登录;
- 截取到的token等信息,是否可以在其他终端上直接使用,绕开登录。Token过期时间校验;
- 除了前端校验格式长度,后端是否也校验;
- 登录后输入登录URL,是否还能再次登录?如果能,原登录用户是否变得无效
- 其他终端修改密码后,原记住密码终端是否提示密码已更改;
- 检查HTTP头的refer URL是否为登录起始页的URL,如果不同是否给出正确的提示并做日志记录和报警;
- 对某些系统,还要验证客户端证书是否与用户名匹配,不匹配时、或者客户端证书过期以及即将过期三种情况是否正确处理和提示;
- 已登录用户,杀死APP进城后,再次打开APP是否依然为登录状态;
- 对于银行系统,密码输入框是否可以正常调用密码控件;(补充:在不同安装证书的环境下)
02 | 如何设计一个“好的”测试用例?
其实在实际项目工作当中,软件生命周期内都会有不同的类型测试。比如,传统软件的开发阶段通常会有单元测试,软件模块集成阶段会有代码级集成测试,打包部署后悔有面向终端用户的GUI测试;再比如,电商网站的测试会分为服务端基于API的测试、中间件测试、前端GUI测试等。
那么一个“好的”测试用例必须具备哪些特征?
- 整体完备性:“好的”测试用例一定是一个完备的整体,是有效测试用例组成的集合,能够完全覆盖测试需求;
- 等价类划分的准确性:是对于每个等价类都能保证只要其中一个输入测试通过,其他输入也一定测试通过;
- 等价类集合的完备性:需要保证所有可能的边界值和边界条件都已经正确识别;
但对于大多数软件测试而言,综合使用等价类划分、边界值分析和错误推测这三大类方法就足够了。
第一、等价类划分方法
等价类中任意一个输入数据对于揭露程序中潜在错误都具有同等效果。后续我们只要从每个等价类中任意选取一个值进行测试,就可以用少量具有代表性的测试输入取得较好的测试覆盖结果。
- 有效等价类:年按人类最高年龄120岁推算,有效年份应为2019~1899年中间;月应为1~12月;日应为1~31日;
- 无效等价类:年小于1899年或大于2019年;月等于00或大于12;日等于00或大于31日;
第二、边界值分析方法
是对等价类划分的补充,从工程实践经验中可以发现,大量的错误发生在输入输出的边界值上,所需要对边界值进行重点测试,通常选取正好等于、刚刚大于或刚刚小于边界的值作为测试数据。
- 选取闰年非闰年20040229以及20050228;大小月日期20000630以及2000731;
第三、错误推测方法
是基于对被测软件系统设计的理解、过往经验以及个人直觉,推测出软件可能存在的缺陷,从而有针对性的设计测试用例的方法。这个方法强调的是对被测试软件的需求理解以及设计实现的细节把握,当然还有个人的能力。
- 身份证号不可重复;数据库链接失败;
在具体设计用例时,首先需要搞清楚每一个业务需求所对应的的多个软件功能需求点,然后分析每个软件功能需求点对应的多个测试需求点,最后再针对每个测试需求点来设计测试用例。
具体到测试用例本身的设计,还有两个关键点需要注意:
- 从软件功能需求出发,全面地、无遗漏地识别出测试需求是至关重要的,这将直接关系到用例的测试覆盖率。(比如,如果你没有出用户登录功能的安全性测试需求,那么后续设计的测试用例就完全不会涉及安全性,最终造成重要测试漏洞。)
- 对于识别出的每个测试需求点,需要总和运用等价类划分、边界值分析和错误推测方法来全面地设计测试用例。需要注意的是,要综合运用这三种法法,并针对每个测试需求点的具体情况,进行灵活选择。
- 以“用户登录”的功能性测试需求为例,我们首先应该对“用户名”和“密码”这两个输入项分别进行等价类划分,列出对应的有效等价类和无效等价类,对于无效等价类的识别可以采用错误推测法(如用户名包含特殊字符等),然后基于两者可能的组合,是基础第一批测试用例。
- 等价类划分完后,我们还需要补充“用户名”和“密码”这两个输入项的边界值的测试用例,比如用户名为空(NULL)、用户名长度刚好大于允许长度等。
设计测试用例的其他经验:
- 需要深入理解被测试软件的架构,对内部的架构有清楚的认识,比如数据库连接方式、数据库的读写分离、消息中间件的配置、缓存系统的层级分布、第三方系统的集成等。
- 必须深入理解被测软件的设计与实现细节,深入理解软件内部的处理逻辑。
- 单单根据测算需求点设计的用例,只能覆盖“表面”的一层,往往覆盖不到内部的处理流程、分支处理,而没有覆盖到的部门就很可能出现缺陷遗漏。在具体实践中,你可以通过代码覆盖率指标找出可能的测试遗漏点。
- 切忌不要以开发代码的实现为依据设计测试用例。因为开发代码实现的错误会导致测试用例也出错,所以你应该根据原始需求设计测试用例。
- 在实际测试工作当中我们还可以建立常见缺陷知识库,那么在用例设计的过程中,会使用缺陷知识库作为检查点列表,去帮助优化补充测试用例的设计。
03 | 什么是单元测试?如何做好单元测试?
单元测试是指,对软件中的最小可测试单元在与程序其他部分相隔离的情况下进行检查和验证的工作,这里的最小可测试单元通常是指函数或者类。
如何做好单元测试?
- 首先必须要弄清楚单元测试的对象是代码,以及代码的基本特征和产生错误的原因,然后我们必须要掌握单元测试的基本方法和主要技术手段,比如,什么事驱动代码、桩代码和Mock代码等。
第一,代码的基本特征与产生错误的原因
- 无论是开发语言还是脚本语言,都会有条件分支、循环处理和函数调用等最基本的逻辑控制,如果抛开代码需要实现的具体业务逻辑,仅看代码结构的话,所有的代码都是在对数据进行分类处理,每一次条件判定都是一次分类处理,嵌套的条件判定或者循环执行,也是在做分类处理。
- 如果有任何一个分类遗漏,都会产生缺陷;如果有任何一个分类错误,也会产生缺陷;如果分类正确也没有遗漏,但是分类时的处理逻辑错误,也会产生缺陷。
在具体工程实践中,开发工程师为了设计并实现逻辑功能正确的代码,通常会有如下的考虑过程:
- 1)如果要实现正常的功能逻辑,会有哪几种正常的输入;
- 2)是否有需要特殊处理的多种边界输入;
- 3)各种潜在非法输入的可能性以及如何处理;
而现在很多公司都省略了单元测试这一过程。主要原因在于敏捷开发阶段,周期短、迭代快,开发诵读也要快的情况下,省略单元测试可以节约很大的时间成本以及人力成本。
但放在长远的时间线上来看,因为不停的在迭代会让原先成立的接口出现一些隐患的bug,而导致不知道是那里出了问题,再去查找定位难免就会多浪费时间,这时候单元测试的作用就体现了,每次迭代的功能代码与测试代码对应,跑一遍测试代码就知道哪里出了问题,可及时修改。
04 | 为什么要做自动化测试?什么样的项目适合做自动化测试?
自动化测试,是把人对软件的测试行为转化为由机器执行测试行为的一种实践,对于最常见的GUI自动化测试来讲,就是由自动化测试工具模拟之前需要人工在软件界面上各种操作,并且自动验证其结果是否符合预期。
自动化测试本质是先写一段代码,然后去测试另外一段代码,所以实现自动化测试用例本身是属于开发工作,需要投入大量时间和精力,并且已经开发完成的用例还必须随着被测对象的改变而不断更新,还需要为此付出维护测试用例的成本,而当维护成本高于其节省的测试成本时,自动化也就失去了价值与意义,我们也就需要在是否使用自动化测试上做权衡取舍了。
为什么需要自动化测试?
优势:
- 可代替大量手工机械重复性操作;
- 大幅度提升回归测试效率,适合敏捷开发过程;
- 更好的利用无人值守时间,去频繁的执行测试;
- 可以高效实现某些手工测试无法完成或者代价巨大的测试类型(如关键业务要7*24小时持续运行的系统稳定性和测试高并发场景的压力测试等);
- 可以保证每次测试执行的操作以及验证的一致性和可重复性,避免人为的遗漏和疏忽;
劣势:
- 无法取代手工测试,它只能替代手工测试中执行频率高、机械化的重复步骤;
- 比手工测试要脆弱,无法应对被测系统的变化,它并不‘智能’,只按部就班的执行事先定义好的测试步骤并验证测试结果。对于执行中出现的明显错误和意外事件,自动化测试没有任何处理能力;
- 自动化测试用例的开发工作量远大于单次的手工测试,所以只有当开发完成的测试用例的有效执行次数大于5次时,才能收回自动化测试的成本;
- 手工测试发现bug数量通常比自动化测试的要多,并且自动化测试仅仅能发现回归测试范围的bug;
- 实行自动化测试的初期,用例开发效率通常都很低,大量初期开发的用例通常会在整个自动化测试体系成熟,和测试工程师全面掌握测试工具后,需要重构。
什么样的项目适合自动化测试?
- 需求稳定,不会频繁变更;
- 研发和维护周期长,需要频繁执行回归测试;
- 需要在多种平台上重复运行相同的场景
- 某些测试项目通过手工测试无法实现,或者手工成本太高;
- 被测软件的开发较规范,能够保证系统的可测试性
总之,对于一些中长期项目,对比较稳定的软件功能进行自动化测试,对变动较大或者需求暂时不明确的功能进行手工测试,最终目标是用20%的精力去覆盖80%的回归测试。
05 | 你知道软件开发各阶段都有哪些自动化测试技术吗?
其实在软件研发生命周期的各个阶段都有自动化测试技术的存在,对提升测试效率都有很大的作用。
单元测试的自动化技术
首先,单元测试本身就是自动化的,因为它根据软件详细设计采用等价类划分和边界值分析方法设计测试用例,在测试代码实现后再以自动化的方式统一执行。但这仅仅是一部分,并没有完整地描述单元测试“自动化”的内涵。从广义上讲,单元测试阶段的“自动化”内涵不仅仅指测试用例执行的自动化,还应该包含以下五个方面:
- 用例框架代码生成的自动化;
- 部分测试输入数据的自动化生成;
- 自动桩代码的生成;
- 被测代码的自动化静态分析;
- 测试覆盖率的自动统计与分析;
代码级集成测试的自动化技术
代码级集成测试是指将已经开发完成的软件模块放在一起测试。从测试用例设计和测试代码结构来看,它和单元测试非常相似,都是对被测试函数以不同的输入参数组合进行调用并验证结构,只不过代码级集成测试的关注点,更多的是软件模块之间的接口调用和数据传递。而与单元测试最大的区别只是,代码级集成测试中被测函数内部调用的其他函数必须是真实的,不允许使用桩代码代替,而单元测试汇总允许使用桩代码来模拟内部调用的其他函数。
代码级集成测试对测试框架的要求非常高,这个框架除了可以顺利装载自己的软件模块外,还必须能装载其他相互依赖的模块,做到被测软件模块可运行(Runnable)。
由于代码级集成测试主要应用在早期非互联网的传统软件企业,那时候的软件以“单体”应用居多,一个软件内部包含大量的功能,每一个软件功能都是通过不同的内部模块来实现的,那么这些内部模块在做集成的时候,就需要做代码级集成测试。
而现在的开发理念追求的是系统复杂性的解耦,会去尽量避免“大单体”应用,采用Web Service或者PRC调用的方式来协作完成各个软件功能。所以现在的软件企业,尤其是互联网企业,基本不会去做代码级集成测试,在这里也就不再进一步展开了。
Web Service测试的自动化技术
Web Service测试,主要是指SOAP API和REST API这两类API测试,最典型的是采用SoapUI或Postman等类似的工具。但这类测试工具基本都是界面操作手动发起Request并验证Response,所以难以和CI/CD集成,于是就出现了API自动化测试框架。
对于基于代码的API测试用例,通常包含三大步骤:
- 准备API调用时需要的测试数据;
- 准备API的调用参数并发起API的调用;
- 验证API调用的返回结果;
GUI测试的自动化技术
GUI测试的自动化技术可能是我们最熟悉的,也是发展时间最长、应用最广的自动化测试技术。核心思想是,基于页面元素识别技术,对页面元素进行自动化操作,以模拟实际终端用户的行为并验证软件功能的正确性。
目前,GUI自动化测试主要分为两大方向,传统Web浏览器和移动端原生应用(Native App)的GUI自动化。虽然二者采用的具体技术差别很大,但是用例设计的思路类似。
- 对于传统Web浏览器的GUI自动化测试,业内主流的开源方案采用Selenium,商业方案采用Micro Focus的UFT(前身是HP的QTP);
- 对于移动端原生应用,通常采用主流的Appium,它对iOS环境集成了XCUITest,对Android环境集成了UIAutomator和Espresso。
06 | 你真的懂测试覆盖率吗?
测试覆盖率通常被用来衡量测试的充分性和完整性,从广义的角度来讲,测试覆盖率主要分为两大类,一类是面向项目的需求覆盖率,另一类是更偏向技术的代码覆盖率。
需求覆盖率
需求覆盖率是指测试对需求的覆盖程度,通常的做法是将每一条分解后的软件需求和对应的测试建立一对多的映射关系,最终目标是保证测试可以覆盖每个需求,以保证软件产品的质量。
通常采用ALM,Doors和TestLink等需求管理工具来建立需求和测试的对应关系,并以此计算测试覆盖率。
但是需求覆盖率的统计方式不在适用于现在的敏捷开发模式,所以现在谈到测试覆盖率,大多指的是代码覆盖率。
代码覆盖率
代码覆盖率是指,至少被执行了一次的条目数占整个条目数的百分比。
如果“条目数”是语句,对应的就是代码行覆盖率;如果“条目数”是函数,对应的就是函数覆盖率;如果“条目数”是路径,那么对应的就是路径覆盖率。依此类推,可以得到绝大多数常见的代码覆盖率类型的定义。
- 行覆盖率又称为语句覆盖率,指已经被执行到的语句占总可执行语句(不包含类似C++的头文件声明、代码注释、空行等等)的百分比。这是最常用也是要求最低的覆盖率指标。实际项目中通常会结合判定覆盖率或者条件覆盖率一起使用。
- 判定覆盖又称为分支覆盖,用以度量程序中每一个判定的分支是否都被测试到了,即代码中每个判定的取真分支和取假分支是否各被覆盖至少各一次。比如,对于if(a>0&&b>0),就要求覆盖“a>0&&b>0”为TRUE和FALSE各一次。
- 条件覆盖是指,判定中的每个条件的可能取值至少满足一次,度量判定中的每个条件的结果TRUE和FALSE是否都被测试到了。比如,对于if(a>0&&b>0),就要求“a>0”取TRUE和FALSE各一次,同时要求“b>0”取TRUE和FALSE各一次。
代码覆盖率的价值
统计代码覆盖率的根本目的是找出潜在的遗漏测试用例,并有针对性的进行补充,同时还可以识别出代码中那些由于需求变更等原因造成的不可达的废弃代码。
代码覆盖率的局限性
高的代码覆盖率不一定能保证软件质量,因为代码覆盖率的计算是基于现有代码的,并不能发现那些“未考虑某些输入”以及“未处理某些情况”形成的缺陷。
07 | 如何高效填写软件缺陷报告
缺陷报告是测试工程师与开发工程师交流沟通的重要桥梁,也是测试工程师日常工作的重要输出。
一般我们会觉得这并不是什么难事,毕竟软件企业通常都有缺陷管理系统,比如典型的ALM(以前的Quality Center)、JIRA、Bugzilla、BugFree和Mantis等。当使用这类系统递交缺陷时,会自动生成模板,你只要按照其中的必填字段提供缺陷的详细信息就可以了。
缺陷报告的组成
1)缺陷标题:缺陷标题通常是别人最先看到的部分,是对缺陷的概括性描述,通常采用“在什么情况下发生了什么问题”的模式。
-
首先,对“什么问题”的描述不仅要做到清晰简洁,最关键是要足够具体,切忌不能采用过于笼统的描述。(如:“用户不能正常登陆”“搜索功能有问题”和“用户信息页面的地址栏位置不正确”等,这样的描述会给人“说了等于没说”的感觉,再如,当你发现了一个菜单栏上某个条目缺失的问题,在递交缺陷报告前,通常会去缺陷管理系统搜索一下是否已经有人递交过类似的缺陷。当你以“菜单栏”为关键字搜索时,你可能会得到一堆“菜单栏有问题”的缺陷,如果缺陷标题的描述过于笼统,你就不得不点击进入每个已知缺陷点去看细节描述,这就会大大降低你的工作效率。所以,如果缺陷标题本身就能概括性地描述具体问题,你就可以通过阅读标题判断类似的缺陷是否被提交过,大大提高测试工程师提交缺陷报告的效率。所以,描述“什么问题”的同时还必须清楚地表述发生问题时的上下文,也就是问题出现的场景。)
-
其次,标题应该尽可能描述问题本质,而避免只停留在问题的表面。(如,“商品金额输入框,可以输入英文字母和其他字符”这个描述就只描述了问题的表面现象,而采用诸如“商品金额输入框,没有对输入内容做校验”的方式,就可以透过标题看到缺陷的本质,这样可以帮助开发人员快速掌握问题的本质。).
-
最后,缺陷标题不宜过长,对缺陷更详细的描述应该放在“缺陷概述”里。
2)缺陷概述
- 缺陷概述通常会提供更多概括性的缺陷本质与现象的描述,是缺陷标题的细化。这部分内容通常是开发工程师打开缺陷报告后最先关注的内容,所以用清晰简短的语句将问题的本质描述清楚是关键。
- 缺陷概述还会包括缺陷的其他延展部分,比如你可以在这部分列出同一类型的缺陷可能出现的所有场景;再比如,你还可以描述同样的问题是否会在之前的版本中重现等。在这里,你应该尽量避免以缺陷重现步骤的形式来描述,而应该使用概括性的语句。
3)缺陷影响
- 缺陷影响描述的是,缺陷引起的问题对用户或者对业务的影响范围以及严重程度。
- 缺陷影响决定了缺陷的优先级和严重程度,开发经理会以此为依据来决定修复该缺陷的优先级;而产品经理会以此为依据来衡量缺陷的严重程度,并决定是否要等该缺陷被修复后才能发布产品。
4)环境配置
5)前置条件
- 前置条件是指测试步骤开始前系统应该处在的状态,其目的是减少缺陷重现步骤的描述。合理地使用前置条件可以在描述缺陷重现步骤时排除不必要的干扰,使其更有针对性。
- 比如,某个业务操作需要先完成用户登录,你在缺陷重现步骤里就没有必要描述登录操作的步骤细节,可以直接使用“前置条件:用户已完成登录”的描述方式。
6)缺陷重现步骤
缺陷重现步骤是整个缺陷报告中最核心的内容,其目的在于用简洁的语言向开发工程师展示缺陷重现的具体操作步骤。
通常测试工程师在写缺陷重现步骤前,需要反复执行这些步骤3次以上:一是,确保缺陷的可重现性;二是,找到最短的重现路径,过滤掉那些非必要的步骤,避免产生不必要的干扰。
对于缺陷重现步骤的描述应该尽量避免以下3个常见问题:
- 笼统的描述,缺乏可操作的具体步骤。
- 出现于缺陷重现不相关的步骤。
- 缺乏对测试数据的相关描述。
7)期望结果和实际结果
期望结果和实际结果通常和缺陷重现步骤绑定在一起,在描述重现步骤的过程中,需要明确说明期待结果和实际结果。期待结果来自于对需求的理解,而实际结果来自于测试执行的结果。
通常来讲,当你描述期望结果时,需要说明应该发生什么,而不是什么不应该发生;而描述实际结果时,你应该说明发生了什么,而不是什么没有发生。
8)优先级(Priority)和严重程度(Severity)
缺陷优先级是指缺陷必须被修复的紧急程度,而缺陷的严重程度是指因缺陷引起的故障对软件产品的影响程度。
可见,严重程度是缺陷本身的属性,通常确定后就不再变化,而优先级是缺陷的工程属性,会随着项目进度、解决缺陷的成本等因素而变动。那么,缺陷的优先级和严重程度又有什么关系呢?
- 缺陷越严重,优先级就越高;
- 缺陷影响的范围越大,优先级也会越高;
- 有些缺陷虽然从用户影响角度来说不算严重,但是会妨碍测试或者是自动化测试的执行,这类缺陷属于典型的严重程度低,但是优先级高;
- 有些缺陷虽然严重程度比较高,但是考虑到修复成本以及技术难度,也会出现优先级较低的情况。
9)根原因分析(Root Cause Analysis)
根原因分析就是我们平时常说的RCA,如果你能在发现缺陷的同时,定位出问题的根本原因,清楚地描述缺陷产生的原因并反馈给开发工程师,那么开发工程师修复缺陷的效率就会大幅提升,而且你的技术影响力也会被开发认可。
10)附件(Attachment)
附件通常是为缺陷的存在提供必要的证据支持,常见的附件有界面截图、测试用例日志、服务器端日志、GUI测试的执行视屏等。对于那些很难用文字描述清楚的GUI界面布局的缺陷,你可以采用截图并高亮显示应该关注的区域的方式去提交缺陷报告。
08 | 以终为始,如何才能做好测试计划?
对于很多非产品型的互联网公司,由于采用了敏捷开发模式,的确很少去制定传统意义上的测试计划了,但这并不是说它们就不再制定测试计划了。其实,测试计划依旧存在,只是从原来的一次性集中制定测试计划,变成了以迭代的方式持续制定测试计划。无论对于早期最具典型的瀑布开发模型,还是现在的敏捷开发模型,测试计划的重要性始终没有发生变化。
那么,没有测试计划会怎么样?
- 很难确切地知道具体的测试范围,已经应该采取的具体测试策略;
- 很难预估具体的工作量和所需要的测试工程师数量,同时还会造成各个测试工程师的分工不明确,引发某些测试工作被重复执行而有些测试则被遗漏的问题;
- 测试的整体进度完全不可控,甚至很难确切知道目前测试的完成情况,对于测试完成时间就更难预估准确的时间节点了;
- 整个项目对潜在风险的抵抗能力很弱,很难应对需求的变更以及其他突发事件。
所以,一份好的测试计划要包括:测试范围、测试策略、测试资源、测试进度、和测试风险预估,这五大方面,并且每一部分都要给出应对可能出现的问题的解决办法。
测试范围
测试范围描述的是被测对象以及主要的测试内容。
比如,对于用户登录模块,功能测试既需要测试浏览器端又需要测试移动端,同时还考虑登录的安全和并发性能相关的非功能性需求的测试等。
测试范围的确定通常是在测试需求分析完成后进行,所以确定测试范围的过程在一定程度上也是对测试需求分析的进一步检验,这将有助于在早期阶段就发现潜在的测试遗漏。
同时,由于不可能进行穷尽测试,而且测试的时间和资源都是有限的,所以必须有所取舍,进行有针对性的测试。因此,测试范围中需要明确“测什么”和“不测什么”。
测试策略
测试策略简单来讲就是需要明确“先测什么后测什么”和“如何来测”这两个问题。
重要的项先测,而不重要的项要后测。测试策略会要求我们明确测试的重点,以及各项测试的先后顺序。
比如,对用户登录模块来讲,“用户无法正常登录”和“用户无法重置密码”这两个潜在问题,对业务的影响孰轻孰重一目了然,所以,你应该按照优先级来先测“用户正常登录”,再测“用户重置密码”。
测试策略还需要说明,采用什么样的测试类型和测试方法。这里需要注意的是,不仅要给出为什么要选用这个测试类型,还要详细说明具体的实施方法。
第一,功能测试
- 对于功能测试,我们应该根据测试需求分析的思维导图来设计测试用例。
- 主线业务的功能测试由于经常需要执行回归测试,所以需要考虑实施自动化测试,通常应该先实现主干业务流程的测试自动化。
- 实际操作时,你通常需要先列出主要的功能测试点,并决定哪些测试点适合采用自动化测试,并且决定具体使用说明样的框架和技术。
- 对于需要手工测试的测试点,你要决定采用什么类型的测试用例设计方法,以及如何准备相关的测试数据。
- 另外,我们还要评估被测软件的可测试性,如果有可测试性的问题,需要提前考虑切实可行的变通方案,甚至要求开发人员提供可测试性的接口。
第二,兼容性测试
- 对于兼容性测试来说,Web测试需要确定覆盖的浏览器类型和版本,移动设备测试需要确定覆盖的设备类型和具体iOS/Android的版本等。
- 如果是既有产品,你可以通过大数据技术分析产品的历史数据得出Top30%的移动设备以及iOS/Android的版本列表,那么兼容性测试只需覆盖这部分即可。
- 如果是一个全新的产品,你可以通过TalkingData这样的网站来查看目前主流的移动设备,分辨率大小、iOS/Android版本等信息来确定测试范围。
- 兼容性测试的实施,往往是在过年测试的后期,也就是说需要等功能基本都稳定了,才会开始兼容性测试。当然也有特例,比如,对于前端引入了新的前端框架或者组件库,往往就会先在前期做兼容性评估,以确保不会引入后期无法解决的兼容性问题。
- 兼容性测试用例的选取,往往来自于已经实现的自动化测试用例。因为兼容性测试往往要覆盖最常用的业务场景,而这些最常用的业务场景通常也是首批实现自动化测试的目标。
- 所以,我们的GUI自动化框架,就需要能够支持同一套测试脚本在不做修改的前提下,运行于不同的浏览器。
第三,性能测试
- 对于性能测试,需要在明确了性能需求(并发用户数、响应时间、事务吞吐量等)的前提下,结合被测系统的特点,设计性能测试场景并确定性能测试框架。
- 比如,是直接在API级别发起压力测试,还是必须模拟终端用户行为进行基于协议的压力测试。再比如,是基于模块进行压力测试,还是发起全链路压测。
- 如果性能是背景数据敏感的场景,还需要确定背景数据量级与分布,并决定产生背景数据的技术方案,比如是通过API并发调用来产生测试数据,还是直接在数据库上做批量insert和update操作,或者是两种方式的结合。
- 最后,无论采用哪种方式,都需要明确待开发的单用户脚本的数量,以便后续能够顺利组装压测测试场景。
性能测试的实施,是一个比较复杂的问题。首先,需要根据你想要解决的问题,确定性能测试的类型;然后,根据具体的性能测试类型开展测试。
- 性能测试的实施,往往先要根据业务场景来决定需要开发哪些单用户脚本,脚本的开发会涉及到很多性能测试脚本特有的概念,比如思考时间、集合点、动态关联等等。
- 脚本开发完成后,你还要以脚本为单位组织测试场景(Scenario),场景定义简单来说就是百分之多少的用户在做登录、百分之多少的用户在做查询、每个用户的操作步骤之间需要等待多少时间、并发用户的增速是5秒一个,还是5秒2个等等。
- 最后,才是具体的测试场景执行。和自动化功能测试不同,性能测试执行完成后性能测试报告的解读,是整个测试过程中最关键的点。
测试资源
测试资源通常包括测试人员和测试环境,这两类资源都是有限的。测试计划的目的就是,保证在有限资源下的产出最大化。所以,测试资源就是需要明确“谁来测”和“在哪里测”这两个问题。
测试人员是最重要的,直接关系到整个测试项目的成败和效率。测试人员的资源通常有两个维度:一是,测试工程师的数量;二是,测试工程师的个人经验和能力。
你会发现,测试工程师的经验和能力不足,很难通过测试人员的数量来弥补。相反地,测试工程师的经验和能力都非常强的情况下,测试人员的数量可以适当地减少。
通常在测试团队中,测试工程师既有资深,也会有初级,那么你就必须针对团队的实际情况去安排测试计划。比如,难度较大的工作,或者一些新工具、新方法的应用,又或者自动化测试开发工作,通常由资深的测试工程师来承担;而那些相对机械性、难度较小的工作,则由初级工程师完成。
可见,你想要规划好测试资源,除了要了解项目本身外,还必须对测试团队的人员特点有清晰的把控。另外,我强烈建议你把具体的任务清晰地落实到每个人的身上,这将有利于家里清晰的责任机制,避免后续可能发生的扯皮。
相对于测试人员,测试环境就比较好理解了。不同的项目,可能会使用共享的测试环境,也可能使用专用的测试环境,甚至还会直接使用生产环境。另外,对于目前一些已经实现容器化部署与发布的项目,测试环境就会变得更简单与轻量级。
测试进度
在明确了测试范围、测试策略和测试资源之后,我们就要考虑具体的测试进度了。测试进度主要描述各类测试的开始时间,所需工作量,预计完成时间,并以此为依据来建议最终产品的上线发布时间。
比如,版本接收测试(Build Acceptance Test)的工作量,冒烟测试(Smoke Test)的工作量,自动化脚本开发的工作量,缺陷修复的验证工作量,需要几轮回归测试、每一轮回归测试的工作量等等。
在传统瀑布模型中,测试进度完全依赖于开发完成并递交测试版本的时间。如果开发提交测试版本发生了延误,那么在不裁剪测试需求的情况下,产品整体的上线时间就同样会延期。然而在敏捷模式下,测试活动贯穿于整个开发过程,很多测试工作会和开发工作同步进行,比如采用行为驱动开发(Behavior-Driven Development)模式,这样测试进度就不会完全依赖于开发递交可测试版本的时间。
测试风险预估
俗话说,计划赶不上变化,对于测试也是一样的道理,很少有整个测试过程是完全按照原本测试计划执行的。通常需求变更、开发延期、发现重大缺陷和人员变动是引入项目测试风险的主要原因。
在敏捷开发与测试中,对于需求的频繁变更(如新加需求、删减需求、修改优化需求等),一定要重新进行测试需求分析,确定变更后的测试范围和资源评估,并与项目经理和产品经理及时沟通因此引起的测试进度影响。测试经理/测试负责人切忌不能有自己咬牙扛过去的想法,否则无论是对测试团队还是对产品本身都不会有任何好处。
另外,随着测试的开展,你可能会发现前期对于测试工作量的预估不够准确,也可能发现需要增加更多的测试类型,也可能发现因为要修改测试架构的严重缺陷而导致很多的测试需要全回归,还有可能出现开发递交测试版本延期,或者人员变动等各种情况。
所以,在制定测试计划时,你就要预估整个测试过程中可能存在的潜在风险,以及当这些风险发生时的应对策略。