
分层测试
分层测试
分层测试是通过对质量问题分类、分层来保证整体系统质量的测试体系。
模块内通过接口测试保证模块质量,多模块之间通过集成测试保证通信路径和模块间交互质量,整体系统通过端到端用例对核心业务场景进行验证,用户体验通过手工测试确保无妨碍用户的交互。
分层测试实现代码、服务、界面分层测试的整体架构目标,逐层建设完善自动化测试能力,逐步做到在保证质量的前提下提升需求交付效率。
可以这么说,当你遇到对一个系统进行整体保障,不知道怎么入手的时候,进行分层测试是一个良好的解决思路。
分层测试的优点
层次分明:各层测试目标清晰,能形成效果叠加,增强质量防护能力。
支持日构建:整个体系支持日构建,支持MR后自动构建,提升开发团队安全感,提升发布效率。
白盒测试:加强了对代码实现逻辑的理解,提升整体代码质量和设计质量。
分层测试的原则
稳定性:稳定性是自动化用例的生命线。
有效断言:用例无断言,就是耍无赖。
测试下沉:要小不要大,自动化用例尽量下沉,用接口用例覆盖。
三早:早测试,早发现,早修复。
聚焦业务: 尽量专注于业务场景,确保每个测试都有价值。
复用业务设施: 依靠基础设施及代码,降低基础设施引入的变化对用例稳定性的影响。
数据独立: 测试数据独立,降低测试数据耦合引入的用例维护复杂性。
分层测试分布图
单元测试
什么是单元测试
对代码中的逻辑隔离的最小代码片段进行测试,验证其逻辑是否符合预期,单元可以是函数,方法,类,功能模块。
单元测试的优点
掌握代码:单元测试允许开发人员了解单元提供的功能以及如何使用它以获得对单元 API 的基本了解。
回归测试:单元测试允许程序员改进代码并确保模块正常工作。
尽早测试:单元测试可以测试项目的某些部分,而无需等待其他部分完成。
测试左移:在软件开发的早期定位和解决错误。
提升复用度:使代码的可重用性更可行。
单元测试的挑战
时间成本:编写单元测试会增加开发人员工作量,单元测试跟生产代码是一样的,并不会因为是用来测试的就有所不同,开发人员同样要面对测试代码的编写,维护等工作,要将单元测试代码写好非常考验开发人员编码能力和测试代码设计能力。
资源投入:推广和让单元测试发生作用投入比较大,只有让每个开发同学都编写足够好,足够稳定的单元测试代码,才能真正享受单元测试带给我们的好处,在达到这种程度之前,需要非常多的资源投入。
单元测试原则
1. 写出合适的测试名称
编写测试时要考虑的基本事项是选择测试名称。这非常重要,因为好的测试名称可以提高程序员和将来可能使用该代码的其他人的代码的可读性。可以在单元测试中应用标准命名约定。
2. 创建简单的测试
保持测试代码尽可能简单是维护代码的关键。单元测试代码也可能有错误,尤其是在高度复杂的情况下。测试不需要很花哨。因此,逻辑、手动字符串或所述圈复杂度等功能应该最少。
3. 幂等性测试
只要代码保持不变,无论输入如何,测试总是会产生相同的结果。这最大限度地减少了误报和漏报的发生率。测试需要是幂等性的,因为呈现可变结果的测试是不可信的。要使测试具有幂等性,它必须与其他测试用例、环境值和外部依赖性隔离开来。
4. 解决单个使用场景
每个测试都应该只用于测试单个使用场景。这将更更易验证代码输出和更好地洞察所发现错误的原因,而无需怀疑问题是否是误报。
5. 最小化测试依赖
当测试不依赖于其他软件部分时,它们的稳定性是最好的。外部因素也不应该影响测试的结果。
6. 测试自动化
尽管可以手动进行单元测试,但当前的做法鼓励使用自动化单元测试方法。事实证明,它不仅高效、便宜,而且省时。单元测试是DevOps 自动化工具执行的一项基本功能,可简化编码过程。
接口测试
什么是接口测试
接口测试是通过测试模块接口来检测模块整体逻辑是否符合预期的测试方法。
接口测试主要用于检测外部模块和模块接口数据交换、关键业务数据状态变化。
测试的重点是要检查数据的交换,传递和控制管理过程,以及模块间的相互逻辑依赖关系等。
接口测试的类型
在我们现在的业务中,主要包含了两种类型的接口测试,分别是单模块接口测试和子系统接口测试。
单模块接口测试
接口测试代码与被测试的接口同源,在测试代码中将依赖的外部服务mock掉,数据库不mock,测试代码与被测试代码在同一个进程。
子系统接口测试
接口测试代码与被测试的接口同源,测试代码与被测试代码在不同进程。
接口测试的优点
接口测试以保证系统的正确稳定为目标,重要性主要体现在:
简化系统: 接口测试可以将复杂的系统关联进行简化,只要做好每个接口的测试就能较好地保证系统质量。
验证接口变更:单个系统的变更,是否会影响到其他系统对该系统的调用。常规的方法很难覆盖相关系统,但是通过接口测试就可以验证其他系统对该系统接口的调用。
减少时间成本:接口功能比较单一,能够比较好的进行测试覆盖,也相对容易实现自动化持续集成,可以减少人工回归成本与时间,缩短测试周期。
测试简单:接口相对于界面功能,会更底层一些,测试覆盖会更容易(如业务在调用接口时做了判断,当不满足条件时链接就不显示,此时从界面无法测试相关功能是否做好判断,通过接口就比较容易)
用户角度: 接口测试从用户的角度对系统接口进行全面检测。实际项目中,接口测试会覆盖一定程度的业务逻辑 。
接口测试的缺点
验证场景有限:只能验证预期范围内的问题,接口测试是根据产品需求和后端架构而产生的,设计的所有用例均是接口设计人员所预期到的结果,无法测试出一些不可预见的问题。
依赖测试分析: 接口测试效果对测试分析的依赖性极大。
接口测试设计最佳实践
接口测试的用例设计和单元测试有相似之处,都需要用到边界值法、等价类法等基本测试方法。
出发点
设计接口测试用例的出发点是要验证接口实现的功能和性能指标是否与接口文档保持一致。
同时,测试接口需要具有良好的容错机制,能在接收到各种异常输入数据时做到错误定位。
选择合适的测试对象
对一个系统做接口测试,识别出合理的测试对象才能保证接口测试达到预期效果,甚至能达到事半功倍的效果。
一个系统可能有很多的层次结构,也就有了不同层级的许多接口,如果对每个接口分别进行测试,时间和人力消耗较大,且用例数量大,用例的维护成本很大。
分析出系统的关键模块和核心接口,并对其进行完整的测试,能以最小的测试投入,达到最好的测试效果。
接口测试用例包括的内容
接口测试用例的内容包括:输入参数组合、预期结果、实际运行结果以及备注的其他相关信息,如:测试功能点说明,测试环境说明等。
预期结果包括接口返回值以及接口的输出参数的内容。
输入参数的组合应遵循等价类法和边界值法等常用用例设计方法,以最少的用例数量覆盖所有典型参数组合,做到每条用例覆盖不同的测试点,且每条用例都不可被取代。
接口测试的设计方法
接口测试的依据往往是需求规格说明书等软件设计文档,测试手段是把接口内的程序逻辑看作一个黑盒
只根据接口定义来编写测试代码,相当于把一个接口当作一个函数来进行测试
为了确保测试的覆盖率,可能会使用到单元测试的用例设计方法。
设计正常场景用例
根据该接口实现的功能分析出该接口的正常用例包括哪几种输入参数的组合,从而在用例中构造相应的参数组合来覆盖所有的正常分支。
输入参数分为两种类型:
第1种是可以直接赋值的,这种参数直接赋值即可。
第2种是其他接口调用的输出参数,无法直接给出,这种参数就需要在调用被测接口前先调用其他接口,将其输出参数作为被测接口所需要的输入参数传入,或者事先将所需要的参数数据写入文件中,通过读取文件的方式获取输入参数的数据。
对接口输入参数的组合,需要考虑两点:
控制用例数: 需要根据自然逻辑进行排列组合,排除无效的组合,以及将可以划分等价类的组合进行合并同类项,控制用例总数,避免冗余重复的用例耗费测试资源。
从业务分析特殊组合: 还应从业务上分析有没有特殊的组合是没有考虑到的,此类用例往往不止涉及单一接口,而是涉及到根据某个特定业务流程而产生的接口调用流程,通过接口调用的方式模拟关键业务流程,可以在不用搭建辅助测试环境的情况下单纯的测试被测接口,去除测试环境复杂性对测试结果的影响,极大提升测试效率。
设计异常场景用例
选取一条正常用例的数据作为基础数据,然后遍历所有的输入参数,针对每一个输入参数,分别使用等价类法,边界值法等用例设计方法枚举出该参数的所有异常值。
该用例除了该参数为异常外,其余参数均保持正常值不变,以保证测试结果仅由异常的那一个参数导致。
当所有输入参数都使用上述方法设计了对应的异常用例之后,进一步补充不方便在用例文件中输入的异常参数到测试脚本中,通过 switch 分支判断,在测试脚本中将无法通过文件读取的异常输入值(如:错误指针等),直接赋值给接口的输入参数,测试某些指针类型的数据错误是否被及时捕获并返回正确无歧义的错误码。
错误码
1.注意错误码返回
在接口设计中,任何时候都应该返回定义好的错误码,绝不能让程序异常退出,或者把未经任何处理的异常信息直接抛出。
程序的异常退出,会产生恶劣的用户体验,也无法进行错误排查。
把未经处理的异常信息抛出,有可能把不应该被使用者感知的信息暴露出来,比如数据库相关信息,从而产生安全隐患。
2. 错误码的准确性很重要
错误码的准确性对接口调用失败原因的定位有非常重要的意义,将极大降低后续维护成本,错误码的设置应当准确,无歧义,一种错误类型一个错误码,尽量将错误码编得更细,更有利于错误排查。
3. 错误码应该是明确含义的
错误码应当在接口设计文档中有明确定义,并且在不同接口中保持一致。
集成测试
什么是集成测试
集成测试是在模块接口的基础上,将所有涉及模块按照设计要求(比如根据架构图)组装成子系统,对系统接口进行正确性校验的测试技术。
通过集成测试可以暴露出这些模块在集成交互时的缺陷,这些缺陷在对各自模块进行接口测试时可能是无法暴露的。
集成测试的模型
可以看到,集成测试的用例模块是跟业务模块独立存在的,并且逻辑也比接口用例要复杂,通过模拟外部使用者行为(有可能是用户,也有可能是其他子系统)的方式,来测试对应的系统或子系统。
集成测试的优点
减少连通性问题:集成测试通过对子系统或系统的全面分析,大大降低了出现严重系统级连通性问题的可能性。
完善测试体系:单模块/接口测试无法发现的问题,在集成测试阶段可以发现。
集成测试的挑战
测试复杂性: 集成测试意味着测试两个或多个集成系统以确保系统正常工作。不仅要测试集成链路,还要进行考虑环境的详尽测试,以确保集成系统正常工作。可能存在可应用于测试集成系统的不同路径和排列。
管理复杂:管理集成测试变得复杂,因为其中涉及的因素很多,例如数据库、平台、环境等。
不同系统的交互:如果测试涉及处理由两个不同供应商创建的两个不同系统,那么就会有关于这些组件如何相互影响和交互的问题。
最佳实践
尽早开始测试
在业务实践中允许同时开发模块,因此需要在早期阶段执行集成测试、检测问题并在开发过程中对业务逻辑进行更改。
这体现了产品开发进度,因为可以更早地检测和修复错误,而无需等待一个模块完成。
此外,如果缺少模块或存在开发中的模块需要联调,可以用Mock来替换它们。
区分业务逻辑和集成测试
单元测试通常速度快且运行时间短。可以在持续集成环境中为每个构建运行它。它旨在对代码进行基本验证,检测业务逻辑中的错误。
但是集成测试需要更长的时间才能运行,并且将它们包含在每个构建中会导致大量时间消耗。可以将它放在靠近日常构建的地方,来降低构建耗时的影响。
记录测试日志
集成测试的范围很广,因为它跨越应用程序中的多个模块。与单元测试不同,在集成测试中没有简单的方法来分析故障的根源。
因此,记录测试结果是发现问题的唯一方法。可以使用一个有效的日志记录框架,提供有关每个测试完成的详细信息。
端到端测试
什么是端到端测试
端到端测试(End-To-End Testing, 简称E2E测试)是一种从头到尾测试整个软件产品以确保应用程序流程按预期运行的技术。它定义了产品的系统依赖性,并确保所有集成部分按预期协同工作。
端到端测试的主要目的是通过模拟真实用户场景并验证被测系统及其组件的集成和数据完整性,主要从最终用户的体验进行测试。
端到端测试的模型
在我们当前的业务实践中,端到端测试由测试同学主导编写,用例代码和业务模块独立仓库管理。
下面按照用户使用银行卡申购指数基金为例,说明端到端测试的依赖关系:
可以看到,端到端测试的用例模块是跟业务模块独立存在的,并且逻辑也比集成测试用例和接口测试都要复杂,通过模拟真实用户行为、打通系统全周期的测试方式,来验证系统的全链路流程。
端到端测试的优点
扩大测试覆盖范围
确保应用程序的正确性
缩短发布时间
降低成本
检测Bug
通过添加比其他测试方法(如单元和功能测试)更详细的测试案例,帮助团队扩大他们的测试范围。
通过运行基于终端用户行为的测试用例,确保应用程序的正确执行。
帮助发布团队缩短上市时间,允许他们自动化关键用户路径。
通过减少测试软件的时间,降低构建和维护软件的总体成本。
端到端测试的挑战
端到端测试也不是万能的,任何收益必然伴随着成本。端到端测试的挑战如下:
编写耗时长
端到端测试需要对产品服务流程有完整的了解才能编写测试用例,因此编写的耗时很长。如果你的产品属于大型产品,那用户在产品中就有很多的浏览途径。我们不能针对每个路径进行测试。
所以,通常做法是更频繁地使用单元测试、接口测试,只对最高优先级的用户工作流使用端到端测试。
测试用例设计难度大
因为端到端测试是模拟用户的真实行为,因为在设计这些测试用例时就需要考虑多许多因素。
比如,一个在多浏览器运行的web程序,每个浏览器都有不同的规范。这意味着我们需要针对不同浏览器编写测试。时间成本很高。
在开发过程中,不能依赖端到端测试来快速寻找代码反馈,而是应该使用单元测试和接口测试。
容易终端且难以维护
端到端测试因为要走完完整流程,流程长,涉及系统多,非常容易中断,用例的前置依赖也非常多,这些都强依赖一个稳定的服务测试环境。整体维护成本非常高。
站在用户角度
用户不是在体验功能,而是通过产品解决他们的某些问题。所以端到端测试应该侧重于如果有效有效地解决用户问题。
并不是所有的开发团队都详细了解用户意图的。所以在开发期间就必须尽快部署,快速收集用户反馈。
端到端测试的最佳实践
要进行端到端测试,遵循以下概述的做法至关重要,以确保测试顺利进行和成本可控。
优先考虑最终用途
模拟用户:创建测试用例时,像用户一样进行测试。了解第一次使用该应用程序的人的心态。
易用性:是否容易找到所有选项?特征有标注吗?用户能否通过两步或三步得到他们想要的东西?
文档先行:使用有助于阐明用户观点的验收测试文档和用户故事,相应地设计测试用例。
考虑投入产出:将 E2E 测试重点放在失败会导致最大问题的应用程序功能上。从这些特性开始,设计更精细的测试用例来验证它们。
避免异常测试
E2E 测试最适合用于测试常见的用户场景。对于特殊的用户场景,使用单元测试或接口测试。
维护整体用例的代码结构
由于 E2E 测试涵盖整个应用程序,因此测试用例必然很复杂。
每个系统组件都必须进行测试,这增加了故障点以及调试每个异常的难度。
结构和组织在 E2E 测试中至关重要。
通过单元测试和接口测试等底层测试消除简单的错误。
优化环境和清理机制
确保测试环境随时可以开始测试。
测试完成后,务必清理测试数据,以便环境恢复到原始状态,从而准备好再次进行测试。
鉴于端到端测试的重要性,需要从项目一开始就对其进行规划。端到端测试最好手动进行,因为它允许测试人员设身处地为用户着想。如果需要自动化测试,最好将其限制在只需要重复操作的低风险功能上。
UI测试
什么是UI测试
UI测试是通过测试产品的视觉元素来验证产品功能和性能的测试技术。
视觉元素的范围很广,包括一切可视化的组件,比如图标、按钮、文本框、颜色、字体、选择框、窗口、菜单等等。
UI测试主要关注产品的功能、可用性、视觉性,也就是用户关心的部分,确保程序成功运行。
注意:当分层测试的其他层次不完备的时候,最好不要考虑使用UI测试,在业务实践来看,准确率很难达标,严重影响开发人员对测试人员信心。
UI测试的类型
手工测试
手工测试由人工测试人员执行,他们根据一组测试用例来评估程序的界面。手工测试十分耗时,而且覆盖率较低。尤其是当涉及到跨设备、跨浏览器、跨环境等测试的时候,很依赖于测试人员的技术素质和业务素质。
基于录制回放的测试
录制和回放 UI 测试使用自动化软件,通常需要有限的编码技能或不需要编码技能即可实施。该软件首先记录测试人员执行的一组操作,然后将它们保存为测试,可以根据需要重放并与预期结果进行比较。Selenium IDE是业界比较出名的一个记录和回放工具。
基于模型的测试
这类测试可以将程序运行期间经历的状态通过图结构表示出来。这里是一个工具的例子:基于模型的自动化测试工具:GraphWalker 。
在一个最简单的形式中,需要包含以下步骤:
构建该系统模型
确认输入
了解预期输出
执行测试并断言结果
UI测试的模型
UI测试的挑战
UI变动频繁:应用程序界面经常被重新设计以提供新的功能。当频繁出现改进时,严格的 UI 测试变得困难。
运行环境复杂:现代应用程序包括嵌入式框架、复杂的流程图、地图、信息图表和其他数字组件。它增加了 UI 测试的挑战。
运行时间太长: 创建有效的 UI 测试用例并运行它们可能需要很长时间,尤其是在测试人员没有使用正确的 UI 测试工具的情况下。
维护成本很高:在短时间内执行许多 UI 测试时,测试人员会花费大量精力创建测试脚本。在这些情况下,解决测试期间的问题变得棘手。
投入产出难度量:测试随着用户界面的变化而变化。因此,UI 测试需要更长的时间,从而延迟交付。最终,很难估计持续运行 UI 测试的 ROI。
UI测试的最佳实践
开发人员和测试人员可以遵循一些最佳实践做法,来减少UI 测试的问题。
限制UI测试用例数量: 使用共享存储库是减少测试维护及其相关成本的一种方法。在第一个测试阶段限制 UI 测试用例的数量也是一个好方法,逐渐增加覆盖范围。
采用无代码方案:为了消除重复更改测试代码的麻烦,开发人员和 QA 团队应该采用无代码自动化解决方案。
进行团队自动化教育:组织的编码文化会显着影响团队在软件开发周期中如何有效地管理测试挑战。由于整个组织都需要特定的代码审查或更改标准,因此他们还可以专注于对团队进行最佳自动化测试实践的教育。
良好的工具选型: 如果没有合适的自动化 UI 测试工具,测试人员将不得不手动测试用户界面,这既费时又费力。因此,选择一个合适的工具就十分重要。