Hurricance

Less is more


软件测试课程总结 - 01

关于软件测试的一切

软件测试趋势

  • 自动化测试在软件质量工程中的地位发生了质的变化,从原本的“以自动化测试为辅”变成了“以自动化测试为主”。
    • 不仅需要从业务本身出发来对软件进行手工测试验证,还需要掌握完整的自动化测试开发技术来设计自动化测试用例
  • 产品上线周期短, 留给测试的时间有限
    • 需要一套完善的高并发测试执行基础架构的支持
  • 随着自动化测试的规模化,测试数据准备的各种问题被逐渐暴露并不断放大,成为影响自动化测试效率以及稳定性的“拦路虎”。早期的传统测试数据准备方法,无论是从测试数据准备的时间成本,还是从测试数据的稳定性和测试数据创建的便利性上看,都已经很难适应大规模自动化测试的要求。
    • 系统性地思考如何才能将测试数据的准备工具化,服务化,最终实现平台化。

成长要求

  1. 成为互联网时代合格的测试工程师
  • 具有快速学习的能力, 能迅速掌握被测软件的业务功能与内部架构,并在此基础上运用各种测试方法,尽可能多地发现潜在缺陷,并能够在已知缺陷的基础上进一步发现相关的连带缺陷。
  • 从知识体系上看,需要有比开发人员更全面的计算机基础知识,还需要了解互联网的基础架构、安全攻击、软件性能、用户体验和常见缺陷等知识。从测试技术上看,需要能够使用常见的测试框架或者工具,需要具有一定的自动化测试脚本的开发能力,这可以从大量重复的工作中解放出来,然后才能有时间去做更有意思的工作。
  1. 成为互联网时代优秀的测试工程师
  • 优秀的测试工程师关注更多的是软件整体的质量,需要根据业务风险以及影响来制定测试策略,有效控制测试的时间和成本,并且能够对测试框架以及工具做出适合项目需求的选型。
  • 优秀的测试工程师不仅可以娴熟地运用各类测试工具,还非常清楚这些测试工具背后的实现原理,以及多个同类测试工具各自的优缺点和适用场景。
  1. 成为互联网时代的测试架构师
  • 面对大量测试用例的执行,无论是 GUI 还是 API,都需要一套高效的能够支持高并发的测试执行基础架构;再比如,面对测试过程中的大量差异性数据要求,需要统一的测试数据准备平台;再比如,为了可以更方便地和持续集成与发布系统(CI/CD)以解耦的形式做集成,需要统一发起测试执行的接口。

测试用例设计

  • 需求方面
    • 功能性需求
    • 非功能性需求(安全, 性能, 兼容性)
  • 方法
    • 等价类划分(有效等价类, 无效等价类)
    • 边界值分析
    • 错误推测方法

测试受限于时间成本和经济成本, 采用基于风险的驱动模式, 追寻缺陷风险和研发成本之间的平衡

  • 好的测试样例
    • 整体完备性: 一个完备的整体,是有效测试用例组成的集合,能够完全覆盖测试需求。
    • 等价类划分的准确性: 对于每个等价类都能保证只要其中一个输入测试通过,其他输入也一定测试通过。
    • 等价类集合的完备性: 需要保证所有可能的边界值和边界条件都已经正确识别。
    • 需求覆盖率, 代码覆盖率

单元测试

单元测试的用例是一个“输入数据”和“预计输出”的集合

  • 输入数据:
    • 被测试函数的输入参数;
    • 被测试函数内部需要读取的全局静态变量;
    • 被测试函数内部需要读取的成员变量;
    • 函数内部调用子函数获得的数据;
  • 预计输出:
    • 被测试函数的返回值;
    • 被测试函数的输出参数;
    • 被测试函数所改写的成员变量;
    • 被测试函数所改写的全局变量;
    • 被测试函数中进行的文件更新;
    • 被测试函数中进行的数据库更新;

驱动代码: 驱动模块通常包括调用被测函数前的数据准备、调用被测函数以及验证相关结果三个步骤。驱动代码的结构,通常由单元测试的框架决定。

桩代码(Stub): 起到了隔离和补齐的作用,使被测代码能够独立编译、链接,并独立运行。同时,桩代码还具有控制被测函数执行路径的作用。桩函数要具有与原函数完全相同的原形,仅仅是内部实现不同,这样测试代码才能正确链接到桩函数;用于实现隔离和补齐的桩函数比较简单,只需保持原函数的声明,加一个空的实现,目的是通过编译链接;实现控制功能的桩函数是应用最广泛的,要根据测试用例的需要,输出合适的数据作为被测函数的内部输入。

对于 Mock 代码来说,我们的关注点是 Mock 方法有没有被调用,以什么样的参数被调用,被调用的次数,以及多个 Mock 函数的先后调用顺序。所以,在使用 Mock 代码的测试中,对于结果的验证(也就是 assert),通常出现在 Mock 函数中。

对于桩代码来说,我们的关注点是利用 Stub 来控制被测函数的执行路径,不会去关注 Stub 是否被调用以及怎么样被调用。所以,你在使用 Stub 的测试中,对于结果的验证(也就是 assert),通常出现在驱动代码中。

自动化测试

优点:

  • 自动化测试可以大幅提升回归测试的效率,非常适合敏捷开发过程;
  • 自动化测试还可以保证每次测试执行的操作以及验证的一致性和可重复性,避免人为的遗漏或疏忽。
  • 自动化测试可以更好地利用无人值守时间,去更频繁地执行测试,特别适合现在非工作时间执行测试,工作时间分析失败用例的工作模式;

当你发现自动化测试用例的维护成本高于其节省的测试成本时,自动化测试就失去了价值与意义,你也就需要在是否使用自动化测试上权衡取舍了。

取舍:

  • 自动化测试并不能取代手工测试,它只能替代手工测试中执行频率高、机械化的重复步骤。你千万不要奢望所有的测试都自动化,否则一定会得不偿失。
  • 自动测试远比手动测试脆弱,无法应对被测系统的变化,业界一直有句玩笑话“开发手一抖,自动化测试忙一宿”,这也从侧面反映了自动化测试用例的维护成本一直居高不下的事实。其根本原因在于自动化测试本身不具有任何“智能”,只是按部就班地执行事先定义好的测试步骤并验证测试结果。对于执行过程中出现的明显错误和意外事件,自动化测试没有任何处理能力。
  • 手工测试发现的缺陷数量通常比自动化测试要更多,并且自动化测试仅仅能发现回归测试范围的缺陷。
  • 自动化测试用例的开发工作量远大于单次的手工测试,所以只有当开发完成的测试用例的有效执行次数大于等于 5 次时,才能收回自动化测试的成本。
  • 测试的效率很大程度上依赖自动化测试用例的设计以及实现质量,不稳定的自动化测试用例实现比没有自动化更糟糕。
  • 实行自动化测试的初期,用例开发效率通常都很低,大量初期开发的用例通常会在整个自动化测试体系成熟,和测试工程师全面掌握测试工具后,需要重构。

应用场景:

  • 需求稳定,不会频繁变更。
  • 研发和维护周期长,需要频繁执行回归测试。
  • 短期项目手工测试, 长期维护中的变动较大的地方手工测试
  • 需要在多种平台上重复运行相同测试的场景。
  • 性能和压力测试
  • 被测软件的开发较为规范,能够保证系统的可测试性。

单元测试自动化:

  • 测试用例执行自动化
  • 用例框架代码生成的自动化;
  • 部分测试输入数据的自动化生成;
  • 自动桩代码的生成;
  • 被测代码的自动化静态分析;
  • 测试覆盖率的自动统计与分析;

代码级集成测试的自动化技术:

Web Service自动化测试:

  • postman前期测试
  • 后期迁移到API自动化测试框架

GUI自动化测试:

  • Selenium
  • Appium

测试覆盖率

代码覆盖率:

  • 语句覆盖率
  • 判定覆盖(分支覆盖)
  • 条件覆盖

统计代码覆盖率的根本目的是找出潜在的遗漏测试用例,并有针对性的进行补充,同时还可以识别出代码中那些由于需求变更等原因造成的不可达的废弃代码。

缺陷报告

格式:

  • 缺陷标题:缺陷标题通常是别人最先看到的部分,是对缺陷的概括性描述,通常采用“在什么情况下发生了什么问题”的模式。(问题本质)
  • 缺陷概述:缺陷概述通常会提供更多概括性的缺陷本质与现象的描述,是缺陷标题的细化。这部分内容通常是开发工程师打开缺陷报告后最先关注的内容,所以用清晰简短的语句将问题的本质描述清楚是关键。
  • 缺陷影响:缺陷影响描述的是,缺陷引起的问题对用户或者对业务的影响范围以及严重程度。测试工程师准确描述缺陷影响的前提是,必须对软件的应用场景以及需求有深入的理解,这也是对测试工程师业务基本功的考验。
  • 环境配置:环境配置用以详细描述测试环境的配置细节,为缺陷的重现提供必要的环境信息。
  • 前置条件:前置条件是指测试步骤开始前系统应该处在的状态,其目的是减少缺陷重现步骤的描述。合理地使用前置条件可以在描述缺陷重现步骤时排除不必要的干扰,使其更有针对性。
  • 缺陷重现步骤:缺陷重现步骤是整个缺陷报告中最核心的内容,其目的在于用简洁的语言向开发工程师展示缺陷重现的具体操作步骤。操作步骤通常是从用户角度出发来描述的,每个步骤都应该是可操作并且是连贯的,所以往往会采用步骤列表的表现形式。通常测试工程师在写缺陷重现步骤前,需要反复执行这些步骤 3 次以上:一是,确保缺陷的可重现性;二是,找到最短的重现路径,过滤掉那些非必要的步骤,避免产生不必要的干扰。
  • 期望结果和实际结果
  • 优先级(Priority)和严重程度(Severity):严重程度是缺陷本身的属性,通常确定后就不再变化,而优先级是缺陷的工程属性,会随着项目进度、解决缺陷的成本等因素而变动。
  • 变通方案
  • 根原因分析(Root Cause Analysis)
  • 附件

测试计划

  • 测试范围
  • 测试策略
    • 功能测试
    • 性能测试
    • 兼容性测试
  • 测试资源
  • 测试进度
  • 测试风险预估

测试范围需要明确“测什么”和“不测什么”;测试策略需要明确“先测什么后测什么”和“如何来测”;测试资源需要明确“谁来测”和“在哪里测”;测试进度是需要明确各类测试的开始时间,所需工作量和预计完成时间;测试风险预估是需要明确如何有效应对各种潜在的变化。

软件测试工程师核心竞争力

传统测试工程师:

  • 测试策略设计能力
  • 测试用例设计能力
  • 快速学习能力
  • 探索性测试思维
  • 缺陷分析能力
  • 自动化测试技术
  • 良好的沟通能力

测试开发工程师:

  • 测试系统需求分析能力
  • 更宽广的知识体系

互联网产品的测试策略

GUI测试:手工为主,自动化为辅 API测试:测试重点 单元测试:用于相对稳定和核心的模块上