持续集成 自动化测试心得总结 (一)

时间之弧 · 2019年10月15日 · 4359 次阅读

自动化测试 (Automated Testing),是指把以人为驱动的测试行为转化为机器执行的过程。实际上自动化测试往往通过一些测试工具或框架,编写自动化测试用例,来模拟手工测试过程。比如说,在项目迭代过程中,持续的回归测试是一项非常枯燥且重复的任务,并且测试人员在每天重复劳动的工作之下,也丝毫得不到成长。此时开展自动化测试就能够帮助测试人员从重复、枯燥的手工测试中解放出来,提高测试效率,缩短回归测试时间。一般来说,自动化测试通常都会跟持续集成系统(比如 Jenkins)配合使用。

但在自动化实践过程中,往往会发现理想和现实之间的差距很大。自动化测试的坑,主要体现在以下几方面:

  1. 自动化测试并不能取代手工测试,它只能替代手工测试中执行频率高、机械化的重复步骤;;
  2. 自动化测试远比手工测试脆弱,用例维护成本很高;
  3. 不能指望自动化测试去发现更多新的 BUG,自动化测试能发现的缺陷远远比手工测试少;
  4. 自动化测试用例的开发工作远大于单次的手工测试,产出价值往往在于长期的回归测试,短期内发挥的作用可能不明显;
  5. 实行自动化测试的初期,用例开发效率通常都很低,并且有很大概率后期在功能没有的变化的情况下重构用例;
  6. 自动化测试的效率很大程度上依赖自动化测试用例的设计以及实现质量,不稳定的自动化测试用例比没有自动化更糟糕;

希望借助自动化流程解决的问题

  1. 测试时间紧张,手工测试可能覆盖不全,容易错过某些边界情况;
  2. 模块间强耦合时,单纯从页面进行测试时,比较难深入的发现问题;
  3. 回归测试时,需要投入较大的人力/工时;
  4. 实现手工测试无法达成的测试任务;
  5. 通过编写测试用例,加深对业务/数据的认知,有助于下阶段迭代中发现隐藏的问题;
  6. 作为心跳脚本,监控线上核心流程功能是否正常;

什么样的项目适合自动化测试?

  • 需求稳定,不会频繁变更的系统或模块;
  • 研发和维护周期长,需要频繁执行回归测试;
  • 单个用例需要在多种平台上执行多次,如浏览器兼容性测试、手机系统版本测试等;
  • 通过手工测试无法实现的测试活动,如压力测试;
  • 被测系统的开发流程相对比较规范;

做自动化测试需要具备的能力

  • Coding; 至少要熟悉自动化工具/框架的代码语言,最好有一定的编码能力,同时代码逻辑要清晰,否则不仅不能保证用例的逻辑性、业务性与健壮性等要素,也不能保证效率;
  • 熟悉被测系统; 熟悉被测系统对任何测试人员来说都是最起码的要求;
  • 掌握一个自动化测试框架/工具; 可以根据所掌握的代码,学习一门自动化测试的框架,如 Selenium/Appium/Robot Framework/UI Recorder/TestNG 等;
  • 不断学习,善于学习,知其然知其所以然; “落后就要挨打。”

自动化用例一般在哪个阶段完成

一般落后于新功能的手工测试阶段,可以在手工用例执行完成或功能上线后,再去补充自动化的用例。
自动化不是跟着新需求走,而是测变化的东西对不变东西的影响,一定不要做为了自动化而自动化的工作。

分层自动化测试

在理解分层自动化之前,我们先看一下经典的测试金字塔。

  • UI 层:界面自动化测试。可以看出它的价值最小,它最接近用户真实场景,也容易发现问题,但它的实现成本最高且太容易受外部依赖,容易影响脚本成功率。总体来说,适当的界面自动化测试是有必要的,但是没有必要在 UI 层投入太多;
  • Service 层:接口自动化测试。它的价值居中,覆盖大多数主要的接口是比较合适的。这一层要求测试人员对系统的结构和系统间的调度非常清楚,同时要了解接口逻辑关系,否则接口测试代码很容易遗漏一些异常场景;
  • Unit 层:单元测试。最有价值的测试,但是对测试人员要求比较高,一般由开发人员完成。

通常来说,手工测试是最基本的,可以做到 90% 以上,而对于自动化测试来说,它更像是一件"防弹衣",用来防护身体的主要部位。有人认为自动化率提高了,就可以节省人力,这实际是非常片面的,因为提高自动化率,意味着需要投入更大的人力在维护的成本上。因为系统的需求是在不断变化的,每一个变化都会导致自动化测试用例需要更新调整。
所以,自动化测试做到什么样才算好,也要结合实际情况具体分析。对于 UI 层面的自动化测试,保证少量必要的主流程即可,切勿在这一层面将自动化测试的"防弹衣"变成臃肿的"宇航服";Service 层面的接口自动化测试,应该考虑覆盖大部分的流程,并且可以实现不错的投入/产出比;Unit 层面的单测,从理论上来说,是从源头上保证软件质量的重要手段,但现实是互联网产品真正能全面开展单元测试,并严格控制代码覆盖率的企业还是凤毛麟角。在这样的背景下,自动化测试策略应该采用 “重量级 API 测试,轻量级 GUI 测试,轻量级 Unit 测试”,以求实现快速寻求用户反馈,快速试错,快速迭代更新的目的。

设计用例的基本原则

基本原则

  • 自动化测试用例的范围应该是相对核心的业务内容,即覆盖主体功能的核心测试点和重复执行率较高的模块;
  • 在测试脚本和被测代码都保持不变的情况下,测试用例的结果应该是稳定的,这一点非常重要,在第二篇个人总结中会提到 GUI 测试的稳定性问题;
  • 除非是必要的情况,否则任何用例都应当避免做持久化的操作,以保证环境始终是干净的;
  • Once Written, Run Anytime as Desired ;
  • 不是所有的手工测试用例都可以使用自动化测试来实现,自动化测试替代不了手工测试,两者的有效结合是保证项目质量的关键。
  • 回归测试场景中,测试用例的选择一般以正向为主,逆向为辅;

用例设计原则(基于 Robot Framework 框架)

保持 Case 的独立性

通常来说,一个 Test Suite 下包含了一组相近的或者有关联的 Test Cases。而每一个 Test Case 应该只测试一种场景,根据 case 复杂程度,不同场景同样可大可小,可以是某个单元的测试,也可以是端到端的测试 (E2E),当然也有特殊的写法比如工作流测试和数据驱动。

Case 的独立性有哪些需要关注的点呢?  

首先 Test Suite 内的 Cases 在执行时不应该相互影响,意思是说当我们有随机的跑其中某个 Case 或乱序的跑这些 Cases 时,测试的结果都应该是准确的。Suite level 和 Directory level 同样要注意独立性的问题。系统较为庞杂时,可能会将数百上千的 Cases 放在一起跑,Robot 框架 本身不会规定 Case 执行的顺序,所以从某种程度上来说同一层级的 Cases 是随机执行的。很典型的情况就是,测试用例在本地调试时怎么跑怎么过,放到 Server 上所有 Cases 一起跑的时候就会 Fail,还可能是偶发的,这种情况下就很可能是由于其他 Case 的痕迹影响到了它,查找问题的根源往往比较耗时。

保持 Case 的可迁移性

Case 的可迁移性主要考虑三点 : Case 对执行环境的依赖 ; Case 对外部设备的依赖;Case 对测试对象的依赖。

Case 对执行环境的依赖
尽量减少对执行环境的依赖。举一个例子,你在本地 PC 上使用 rf 框架编写、调试用例后,上传到 Git,然后你的领导可能会拉取你的用例在他的本地运行,随后又被部署到持续集成服务器上。所以你编写的用例时就要尽量避免使用不同平台的库或者 shell 命令。

再举个例子,如果你因为业务需要而修改了测试库源码的话,此时不管是组内其他人还是 CI 服务器,肯定都会运行失败,这种情况该怎么解决呢?这里提供两个解决方法:

  1. 将修改后的库做成测试库,上传到 Git 或者 Pypi,对方可以通过 pip 安装更新;
  2. 使用 robotremoteserver 做一个共享库放在远程主机上,具体请参考虫师的文章

Case 对外部设备的依赖
有时为了业务测试需要,我们会引入一些外部设备来辅助测试,外部设备可能会持续升级或者更换,在编写用例时我们就需要考虑如何用一套 Case 更好的兼容这些测试设备。比如可以将外部设备的操作从测试用例中抽离出去,封装成测试库或关键字;

Case 对测试对象的依赖
如果测试对象是一个软件平台,软件平台通常需要适配多种的设备,而设备的硬件配置可能是多种多样的:CPU、内存、组件的性能和数量都可能不同。对测试对象的依赖不仅要考虑在不同设备上的可执行性,重点还要考虑测试覆盖率。由于设备组件的增多你的用例可能无法覆盖到这些组件,或者捕捉不到某个性能瓶颈,这样测试结果的可靠性也大打折扣。

提升 Case 执行效率

不同的 case 执行时间相距甚远,短则数秒长则持续数天。数秒钟的简单功能测试用例和耗时数天的稳定性测试用例本身是没有什么可比性的。但是我当我们放眼某一个或者某一组 case 时,我们就需要重视 Case 的执行效率。不论是敏捷流程还是持续集成都讲究快速的反馈,开发人员能在提交代码后快速的获得测试结果反馈,测试人员能在最短的时间内执行更大范围的测试覆盖,不仅能提高团队的工作效率,也可增强团队的信心。

以使用 Robot 为例,在编写用例时可以通过以下方面来提高用例的执行效率:

  • 如果有对执行条件的检查,若检查失败,则尽快退出执行;
  • 将数据准备或环境清除等工作抽取成关键字放到更高的层级中,,抽取时可能需要做一些组合, 但不允许出现重复的建删操作;
  • 用例中尽量少的出现 sleep,建议用"wait until ..."来代替;
  • 可以采用并发执行用例的方法来提升效;

自动化用例编写规范

命名规范

Keyword 命名

第一个单词应以小写字母作为开头,后面的单词则用大写字母开头。  如:getProjectId, connectDB

常量命名

常量的名字应该都使用大写字母,并且指出该常量完整含义。如果一个常量名称由多个单词组成,则应该用下划线来分割这些单词。  如:MAX_CHAR_LENGTH     

参数命名

参数的命名规范和方法的命名规范相同,请在尽量保证参数名称为一个单词的情况下使参数的命名尽可能明确。如:account ,investor_name

使用 Tags

RF 提供了通过在 Settings 中设置 tags 来管理用例的方法。Tag 的应用非常的广泛和灵活,比如可以用来做用例筛选、版本管理、统计策略等。

怎么打 tag 看起来会更便捷?

  • 可以在各个文件夹下打文件夹名字的 tag,这样就可以根据 tag 单独的跑该文件夹下的用例,查看测试报告也更好看些;
  • 在一些重要的用例上打上 tag,可以单独跑关键用例;
  • 某些用例如果不想执行,可以打上 tag,设置不执行。

image

让 case 具有文档性

在考虑 Coding Style 时我们可以设置一些固定的规则,大家只要按照这个规则来做,实践几次之后 Coding Style 就会趋于统一. 而考虑将 Case 写的如同文档一般则需要更多的主观能动性。

敏捷开发 (Agile Development) 在国内的发展已经越完善,伴随之而来的便是敏捷测试 (Agile Testing)。敏捷思想强调以人为核心,在整个开发流程中,只写有必要的文档或尽量少写文档,这也是它与传统的瀑布模型的差别。

为了不造成误解,这里有必要插入的说一下敏捷测试的几个特点:

  • 敏捷测试应该是敏捷开发的一部分;
  • 敏捷测试具有鲜明的敏捷开发的特征,如测试驱动开发 (TDD),验收测试驱动开发 (ATDD)。也就是说,单元测试是敏捷测试的基础,如果没有足够的单元测试,就无法应对将来需求的快速迭代,也无法实现快速而稳定的持续交付;
  • 优秀的敏捷测试是基于自动化测试的;
  • 敏捷测试无时不在,无处不在。

需求设计不断的更新,而文档往往不能被很及时的更新,那这样的话怎么才能让测试人员如何快速的掌握某个功能或者产品的需求和当前状态呢?

"Tests as Documentation."

简洁明了的 Documatation

作为用例的补充信息,Documentation 可以大大增强用例的可读性。一个 Suite 文件往往包含了一组测试用例,Suite level 的 Documation 通常可以包含该组测试的背景信息、测试的目的、特殊的环境配置说明等;Case level 的 Documatation 我们觉得一般情况下是不需要的, 因为 case 的结构本身应该足够清楚的描述。
tag.png

清晰易懂的用例名

在实际的工程中,我们可能会新建一个目录来存储测试点相近的测试用例。每一个 Case 都对应一个测试点,而用例名则应该概括总结对应测试点的核心内容,这样当我们在浏览一组用例时,仅仅通过用例名就能大致了解里面的测试内容,也方便寻找某个 Case。
image


参考文档

1.如何写更好的自动化测试用例
2.互联网产品的测试策略应该如何设计? 茹炳晟
3.我的自动化开展思路
4.robot framework 测试用例如何打 tag
5.云服务测试(4)—第 3 章 端到端测试
6.端到端测试 VS 单元测试
7.Robot Framewrok 自动化测试宝典,齐涛/著
8.如何做好自动化测试,揭秘阿里巴巴分层自动化实践之路
9.自动化测试用例设计原则
10.较好的命名规则参考
11.Robot Framework 自动化测试(六)--- robotremoteserver 使用

【To be cintinued...】

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册