软件测试回顾(5)

Web GUI自动化测试

11章:传统产品和互联网产品的测试策略

传统产品和互联网产品的区别

互联网产品:

  • 上线周期短,以“天”甚至是以“小时”为单位
  • 要求全回归测试的执行时间不能超过4小时。

传统产品:

  • 上线周期长,以“月”甚至是以“年”为单位

传统产品测试策略

单元测试 + API测试 + GUI测试

采用GUI自动化测试技术,用例的维护和执行代价依然很大

互联网产品的测试策略

GUI测试 + API测试

互联网产品的GUI测试通常采用“手工为主,自动化为辅”的测试策略,

测试重点放在API测试

  • API测试用例的开发与调试效率比GUI测试要高得多
    • 通常就是准备测试数据,发起request,验证response这几个标准步骤。
  • API测试用例的执行稳定性远远高于GUI测试。
  • 执行时间往往要比GUI测试短很多
  • 对微服务的测试,本质上就是对不同的Web Service的测试,也就是API测试。
  • API接口的改动一般比较少,即使有改动,绝大多数情况下也需要保证后向兼容性(Backward Compatibility)

重量级API测试,轻量级GUI测试,轻量级单元测试

互联网产品的全面单元测试只会应用在那些相对稳定和最核心的模块和服务上,而应用层或者上层业务服务很少会大规模开展单元测试


12章:GUI自动化原理

GUI自动化原理

主要是知道gui的自动化原理

Selenium 2.0,又称Selenium WebDriver,它利用的原理是:使用浏览器原生的WebDriver实现页面操作

Selenium WebDriver是典型的Server-Client模式,Server端就是Remote Server。以下是Selenium 2.0工作原理的解析

  1. 当使用Selenium2.0启动浏览器Web Browser时,后台会同时启动基于WebDriver Wire协议的Web Service作为Selenium的Remote Server,并将其与浏览器绑定。绑定完成后,Remote Server就开始监听Client端的操作请求。
  2. 执行测试时,测试用例会作为Client端,将需要执行的页面操作请求以Http Request的方式发送给Remote Server。该HTTP Request的body,是以WebDriver Wire协议规定的JSON格式来描述需要浏览器执行的具体操作。
  3. Remote Server接收到请求后,会对请求进行解析,并将解析结果发给WebDriver,由WebDriver实际执行浏览器的操作。
  4. WebDriver可以看做是直接操作浏览器的原生组件(Native Component),所以搭建测试环境时,通常都需要先下载浏览器对应的WebDriver。

13章:数据驱动+页面对象(PageObject)模型

数据驱动

在写自动化用例时候,不可以进行硬编码、还需要多代码进行复用,解决方案就是把测试数据和测试脚本分离。也就是说测试脚本只有一份,其中需要输入数据的地方会用变量来代替

这个存放测试输入数据的文件,通常是表格的形式,也就是最常见的CSV文件。

然后,在测试脚本中通过data provider去CSV文件中读取一行数据,赋值给相应的变量,执行测试用例。接着再去CSV文件中读取下一行数据,读取完所有的数据后,测试结束。CSV文件中有几行数据,测试用例就会被执行几次。

这也就是典型的数据驱动(Data-driven)测试了。

  • 数据驱动很好地解决了大量重复脚本的问题,实现了“测试脚本和数据的解耦”
  • 数据驱动测试的数据文件中不仅可以包含测试输入数据,还可以包含测试验证结果数据,甚至可以包含测试逻辑分支的控制变量
  • 数据驱动测试的思想不仅适用于GUI测试,还可以用于API测试、接口测试、单元测试等。

页面对象(PageObject)模型

页面对象模型的核心理念是,以页面(Web Page 或者Native App Page)为单位来封装页面上的控件以及控件的部分操作。而测试用例,更确切地说是操作函数,基于页面封装对象来完成具体的界面操作,最典型的模式是“XXXPage.YYYComponent.ZZZOperation”。

就是利用模块化思想,把一些通用的操作集合打包成一个个名字有意义的函数,然后GUI自动化脚本直接去调用这些操作函数来构成整个测试用例,这样GUI自动化测试脚本就从原本的“流水账”过渡到了“可重用脚本片段”。

  • 解决了脚本可读性差的问题,脚本的逻辑层次也更清晰了;
  • 解决了通用步骤会在大量测试脚本中重复出现的问题,当某个步骤的操作或者界面控件发生变化时,只要一次性修改相关的操作函数就可以了,而不需要去每个测试用例中逐个修改。

个人理解就是对 某一个页面作为一个类,页面里面的操作就是 函数。剩下把细节全部封装在函数内,在调用是使用时候,就不会对细节造成困扰,也提高了可读性。类似:关键字测试


14章:自动化更好描述业务

1.把握封装的函数粒度

很大程度上取决于项目的实际情况,以及测试用例步骤的设计,并没有一个放之四海而皆准的绝对标准。

往往以完成一个业务流程(business flow)为主线,抽象出其中的“高内聚低耦合”的操作步骤集合,操作函数就由这些操作步骤集合构成。

2.衔接好2个操作函数之间的页面

前序操作函数完成后的最后一个页面,必须是后续操作函数的第一个页面。

如果连续的两个操作函数之间无法用页面衔接,那就需要在两个操作函数之间加入额外的页面跳转代码,或者是在操作函数内部加入特定的页面跳转代码。

3.业务抽象流程

业务流程抽象是,基于操作函数的更接近于实际业务的更高层次的抽象方式。基于业务流程抽象实现的测试用例往往灵活性会非常好,你可以很方便地组装出各种测试用例

业务流程的核心思想是,从业务的维度来指导测试业务流程的封装。由于业务流程封装通常很贴近实际业务,所以特别适用于组装面向终端用户的端到端(E2E)的系统功能测试用例,尤其适用于业务功能非常多,并且存在各种组合的E2E测试场景。


15章:GUI自动化中的测试数据

GUI测试中两种常见的数据类型:

  • 测试时输入数据。
  • 事先准备好的测试数据。

在实际项目中,对于创建数据的技术手段而言,最佳的选择是利用API来创建数据,只有当API不能满足数据创建的需求时,才会使用数据库操作的手段。

实际上,往往很多测试数据的创建是基于API和数据库操作两者的结合来完成,即先通过API创建基本的数据,然后调用数据库操作来修改数据,以达到对测试数据的特定要求。

而对于创建数据的时机,在实际项目中,往往是On-the-fly和Out-of-box结合在一起使用。

对于相对稳定的测试数据,比如商品类型、图书类型等,往往采用Out-of-box的方式以提高效率;而对于那些只能一次性使用的测试数据,比如商品、订单、优惠券等,往往采用On-the-fly的方式以保证不存在脏数据问题。

1.基于API调用创建测试数据

由于API通常都有安全相关的token机制来保护,所以实际项目中,通常会把对这些API的调用以代码的形式封装为测试数据工具(Test Data Utility)。

测试数据的准确性直接由产品API保证,缺点是并不是所有的测试数据都有相关的API来支持。

基于API调用方式的执行效率,即使采用了并发机制也不会十分理想

2.基于数据库操作创建测试数据

很多数据的创建和修改直接在产品代码内完成,而且并没有对外暴露供测试使用的接口。

这种情况下,需要通过直接操作数据库的方式来产生测试数据。

同样地,我们可以把创建和修改数据的相关SQL语句封装成测试数据工具,以方便测试用例的使用。

创建或修改一条测试数据往往会涉及很多业务表,任何的遗漏都会造成测试数据的不准确,从而导致有些测试因为数据问题而无法进行。

两个思路来帮你解决这个问题:

  • 手工方式。
    • 查阅设计文档和产品代码,找到相关的SQL语句集合。
    • 直接找开发人员索要相关的SQL语句集合。
  • 自动方式
    • 先在只有一个活跃用户的情况下,通过GUI界面操作完成数据的创建、修改,然后利用数据库监控工具获取这段时间内所有的业务表修改记录,以此为依据开发SQL语句集。

假定产品功能正确,否则就会出现“一错到底”的尴尬局面。

好处:

  • 可以创建和修改API不支持的测试数据,
  • 并且由于是直接数据库操作,执行效率会远远高于API调用方法。

坏处:

  • 经常出现因为SQL语句更新不及时而导致测试数据错误的问题
  • 数据不准确往往只是局部错误,因此这类问题往往比较隐蔽,只有在特定的测试场景下才会暴露。

在实际工程项目中,需要引入测试数据工具的版本管理,并通过开发流程来保证SQL的变更能够及时通知到测试数据工具团队。

3.综合运用API调用和数据库操作创建测试数据

实时创建数据:On-the-fly

GUI测试脚本中,在开始执行界面操作前,我们往往会通过调用测试数据工具实时创建测试数据,也就是On-the-fly方式。

  • 在用例执行过程中实时创建数据,导致测试的执行时间比较长。
  • 业务数据的连带关系,导致测试数据的创建效率非常低。
  • 更糟糕的情况是,实时创建测试数据的方式对测试环境的依赖性很强

事先创建测试数据:Out-of-box

Out-of-box的含义是开箱即用,也就是说,已经在被测系统中预先创建好了充足的、典型的测试数据。这些数据通常是在搭建测试环境时通过数据库脚本“预埋”在系统中的,后续的测试用例可以直接使用

  • 测试用例中需要硬编码(hardcode)测试数据,额外引入了测试数据和用例之间的依赖
  • 只能被一次性使用的测试数据不适合Out-of-box的方式。
  • “预埋”的测试数据的可靠性远不如实时创建的数据。

On-the-fly和Out-of-box的互补

在实际的大型测试项目中,我们往往会采用两者相结合的方式,从测试数据本身的特点入手,选取不同的测试数据创建方式。

  • 对于相对稳定、很少有修改的数据,建议采用Out-of-box的方式,比如商品类目、厂商品牌、部分标准的卖家和买家账号等。
  • 对于一次性使用、经常需要修改、状态经常变化的数据,建议使用On-the-fly的方式。
  • 用On-the-fly方式创建测试数据时,上游数据的创建可以采用Out-of-box方式,以提高测试数据创建的效率。
    • 以订单数据为例,订单的创建可以采用On-the-fly方式,而与订单相关联的卖家、买家和商品信息可以使用Out-of-box方式创建。

16章:自动化GUI自动化测试

  • 页面对象自动生成
  • GUI测试数据自动生成
  • 无头浏览器

1. 页面对象自动生成

页面对象自动生成技术,它非常适用于需要维护大量页面对象的中大型GUI自动化测试项目。

基本思路是,你不用再手工维护Page Class了,只需要提供Web的URL,它就会自动帮你生成这个页面上所有控件的定位信息,并自动生成Page Class。,需要注意的是,那些依赖于数据的动态页面对象也会被包含在自动生成的Page Class里,而这种动态页面对象通常不应该包含在Page Class里,所以,往往需要以手工的方式删除。

很多商用自动化工具,比如UFT,已经支持页面对象自动生成功能了,同时还能够对Page Class进行版本管理。目前国内应用还不算多、免费的Katalon Studio,已经提供了类似的页面对象库管理功能。

2.GUI测试数据自动生成

由机器自动生成测试用例的输入数据。

  • 根据GUI输入数据类型,以及对应的自定义规则库自动生成测试输入数据。
    • GUI界面上有一个“书名”输入框,它的数据类型是string。基于数据类型就可以自动生成诸如 Null、SQL注入、超长字符串、非英语字符等测试数据。
      同时,根据自定义规则库,还可以根据具体规则生成各种测试数据。这个自定义规则库里面的规则。
  • 对于需要组合多个测试输入数据的场景,测试数据自动生成可以自动完成多个测试数据的笛卡尔积组合,然后再以人工的方式剔除掉非法的数据组合。
    • 先手动选择部分输入数据进行笛卡尔积,并删除不合法的部分;然后,在此基础上,再人为添加更多业务上有意义的输入数据组合。
      • 输入数据有A、B、C、D、E、F六个参数,你可以先选取最典型的几个参数生成笛卡尔积,假设这里选取A、B和C;然后,在生成的笛卡尔积中删除业务上不合法的组合;最后,再结合D、E和F的一些典型取值,构成更多的测试输入数据组合。

3.无头浏览器

Headless Browser,是一种没有界面的浏览器。

其实是一个特殊的浏览器,你可以把它简单地想象成是运行在内存中的浏览器。它拥有完整的浏览器内核,包括JavaScript解析引擎、渲染引擎等。

与普通浏览器最大的不同是,无头浏览器执行过程中看不到运行的界面,但是你依然可以用GUI测试框架的截图功能截取它执行中的页面。

  • 测试执行速度更快。
    • 无头浏览器无需加载CSS以及渲染页面
  • 减少对测试执行的干扰。
    • 不可预期的弹出框,对浏览器测试的干扰。
  • 简化测试执行环境的搭建。
    • GUI测试可以直接运行在无界面的服务器上。
  • 在单机环境实现测试的并发执行

它最大的缺点是,不能完全模拟真实的用户行为,而且由于没有实际完成页面的渲染,所以不太适用于需要对于页面布局进行验证的场景。同时,业界也一直缺乏理想的无头浏览器方案。

Puppeteer是由Google开发的,所以它可以很好地支持Headless Chrome以及后续Chrome的版本更新。

selenium + xpath的组合很方便,可以解决大部分的元素识别,chrome浏览器右键拷贝 xpath,很方便,

无头浏览器目前应用的比较少,多是用来做爬虫,说实话老师的这些工具我是一个都没用过


17章:GUI自动化的稳定性

GUI自动化测试稳定性,最典型的表现形式就是,同样的测试用例在同样的环境上,时而测试通过,时而测试失败

要提高GUI测试稳定性,首先你需要知道到底是什么原因引起的不稳定。你必须找出尽可能多的不稳定因素,然后找到每一类不稳定因素对应的解决方案。

造成GUI测试不稳定的因素:

  • 非预计的弹出对话框;
  • 页面控件属性的细微变化
  • 被测系统的A/B测试;
  • 随机的页面延迟造成控件识别失败;
  • 测试数据问题。

非预计的弹出对话框

  • GUI自动化测试用例执行过程中,操作系统弹出的非预计对话框
    • (操作系统突然弹出杀毒软件更新请求、病毒告警信息、系统更新请求等对话框。)
  • 被测软件本身也有可能在非预期的时间弹出预期的对话框
    • 你在网站上进行操作时,很可能会随机弹出“用户调查”对话框。

解决方法

  • 当自动化脚本发现控件无法正常定位,或者无法操作时,GUI自动化框架自动进入“异常场景恢复模式”。
  • 在“异常场景恢复模式”下,GUI自动化框架依次检查各种可能出现的对话框,一旦确认了对话框的类型,立即执行预定义的操作(比如,单击“确定”按钮,关闭这个对话框),接着重试刚才失败的步骤。

页面控件属性的细微变化

登录”按钮的ID从“Button_Login_001”变成了“Button_Login_888”,就会因为ID值的变化,定位不到它了,自动化测试用例自然就会失败。

解决方法

采用“组合属性”定位控件会更精准,而且成功率会更高,如果能在此基础上加入“模糊匹配”技术,可以进一步提高控件的识别率。

  • “模糊匹配”是指,通过特定的相似度算法,控件属性发生细微变化时,这个控件依旧可以被准确定位。
    • 开源的GUI自动化测试框架,目前还没有现成的框架直接支持模糊匹配,通常需要你进行二次开发
      • 实现思路是:实现自己的对象识别控制层,也就是在原本的对象识别基础上额外封装一层,在这个额外封装的层中加上模糊匹配的实现逻辑。

通常,我不建议把模糊匹配逻辑以硬编码的方式写在代码里,而是引入规则引擎,将具体的规则通过配置文件的方式与代码逻辑解耦。

有幸经历过这样的场景,不过我们的方案简单粗暴,就是和前端开发约定规则,例如我们是统一使用id进行定位了,也就是说前端开发不可以随意的更改id。(因为我不是互联网公司,web不经常变化,可以适用约定规则这个路线)

被测系统的A/B测试

A/B测试,是互联网产品常用的一种测试方法。它为Web或App的界面或流程提供两个不同的版本,然后让用户随机访问其中一个版本,并收集两个版本的用户体验数据和业务数据,最后分析评估出最好的版本用于正式发布。

A/B 测试通常会发布到实际生产环境,所以就会造成生产环境中GUI自动化测试的不稳定。

这种问题的解决思路是,在测试脚本内部对不同的被测版本做分支处理,脚本需要能够区分A和B两个的不同版本,并做出相应的处理。

随机的页面延迟造成控件识别失败

解决方法

一个屡试不爽的办法就是,加入重试(retry)机制,当某一步GUI操作失败时,框架会自动发起重试,重试可以是步骤级别的,也可以是页面级别的,甚至是业务流程级别的。

开源GUI测试框架,重试机制往往不是自带的功能,需要自己二次开发来实现。

对于那些会修改一次性使用数据的场景,切忌不要盲目启用页面级别和业务流程级别的重试。

我们是靠经验的加等待时间,后来发现selenium 有一个函数可以设定一个最大超时时间,在这个时间之前都会等待,一旦超时时间内满足了继续执行的条件,也可以立刻执行,既保证了用例操作的预期性,也解决了延迟的不可控的问题

测试数据问题

测试用例所依赖的数据被其他用例修改了;再比如,测试过程中发生错误后自动进行了重试操作,但是数据状态已经在第一次执行中被修改了。

不稳定的自动化是相当耗心血的工作,能彻底把人搞疯,维护者还不出工作量,所以尽可能让gui自动化稳定,多处理,保持一个高的稳定率


18章:GUI自动化的测试报告

理想中的GUI测试报告应该是由一系列按时间顺序排列的屏幕截图组成,并且这些截图上可以高亮显示所操作的元素,同时按照执行顺序配有相关操作步骤的详细描述。

开源GUI测试框架的测试报告实现思路

  • 需要自己去实现截图以及高亮显示操作元素的功能。
    • 利用Selenium WebDriver的screenshot函数在一些特定的时机(比如,页面发生跳转时,在页面上操作某个控件时,或者是测试失败时,等等)完成界面截图功能。
    • 扩展Selenium原本的操作函数;
    • 在相关的Hook操作中调用screenshot函数。

扩展Selenium原本的操作函数实现截图以及高亮显示操作元素的功能

  • 首先,用Javascript代码高亮显示被操作的元素,
    • 高亮的实现方式就是利用JavaScript在对象的边框上渲染一个5-8个像素的边缘;
    • 然后,调用screenshot函数完成点击前的截图;
    • 最后,调用Selenium原生的click函数完成真正的点击操作。

在相关的Hook操作中调用screenshot函数实现截图以及高亮显示操作元素的功能

截图的测试报告的具体数据结构其实是个大的json文件,json中的每个节点元素记录了时间戳,测试用例输出的log,截图文件的保存路径等信息,所以就可以很方便的在报告中同步显示对应的log信息。

操作步骤截图功能,Windows7 系统开始,自带一个「问题步骤记录器」,直接在运行框输入 psr.exe 就可以调起,开启监控后,所有操作步骤的说明和截图都会保存成 MHTML 文件,结束时会打包到一个压缩包中,没用过的推荐试一下。


19章:大型项目中设计GUI自动化测试策略

前提:大型全球化电商网站的前端模块划分

各个前端模块都有各自独立的代码库,除此之外还会有一个公共组件的代码库。

1.大型全球化电商网站的GUI自动化测试策略设计

GUI测试通常只覆盖最核心且直接影响主营业务流程的E2E场景。也应该是分阶段、分层次来设计制定测试策略的

  1. 首先,要从前端组件的级别来保证质量,也就是需要对那些自定义开发的组件进行完整全面的测试
    1. 最常用的方案是:基于Jest开展单元测试,并考量JavaScript的代码覆盖率指标。
    2. 在页面层面再次验证控件相关的功能和状态。
      1. 先构建一个空页面,并加入被测控件,由此可以构建出一个包含被测控件的测试页面,这个页面往往被称为Dummy Page;
      2. 从黑盒的角度出发,在这个测试页面上通过手工和自动化的方式操作被测控件,并验证其功能的正确性。
  2. 每一个前端模块,都会构建自己的页面对象库,并且在此基础上封装开发自己的业务流程脚本。这些业务流程的脚本,可以组装成每个前端模块的测试用例。

以用户管理模块为例,测试用例的组装过程如下:

  • 首先,把用户管理模块中涉及到的所有页面,比如登录页面、用户注册页面等,按照页面对象模型的要求写成Page类;

  • 然后,利用这些Page类封装业务流程脚本,比如用户登录流程,用户注册流程等;

  • 最后,在GUI测试用例脚本中,调用封装好的业务流程脚本构成该模块的GUI测试用例。

    在这个阶段,测试用例需要完整覆盖该模块的所有业务逻辑以及相关的功能测试点,但是并不会实现所有测试用例的自动化。

    自动化测试用例的原则,通常是:优先选取业务关键路径以及Happy Path作为自动化测试的范围。在资源充裕的情况下,我们希望这个阶段的自动化率可以达到70%-80%。 所以,前端模块的质量保证主要依赖这部分测试。

  1. 最后,组合各个前端模块,并站在终端用户的视角,以黑盒的方式使用网站的端到端(E2E)测试。
    1. 探索式测试的方法手工执行测试
    2. GUI自动化测试执行基本业务功能的回归测试(往往是几百个的规模,但是对于保证最终网站的质量却起着非常关键的作用。)

负责这种系统级别的GUI测试,往往被称为E2E测试团队。E2E团队应该尽可能地利用各个模块已有的页面对象和业务流程脚本,组装端到端的GUI测试。

2.大型全球化电商网站的GUI自动化测试脚本管理

将各个模块的页面对象和业务流程脚本放在各自的代码库中,并引入页面对象和业务流程脚本的版本管理机制,通常采用页面对象和业务流程脚本的版本号和开发版本号保持一致的方案。

比如模块A的版本号是V1.0.0,那么对应的页面对象库和业务流程脚本的版本号也应该是V1.0.0。在端到端的GUI自动化测试脚本中,引用各个模块正确的页面对象和业务流程脚本的版本号,测试用例代码就可以直接调用模块的页面对象和业务流程脚本了。

在这种管理机制下,E2E团队不需要重复开发任何的页面对象和业务流程脚本,而且可以始终保证与各个模块的最新实现同步,同时端到端的GUI测试用例脚本也会比较稳定,不会因为各个模块的改动而频繁地修改。

内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/wfer/p/14244383.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!