Telemetry(项目主页)是 Google 为 Chromium 项目所编写的一套性能测试自动化框架。
关于 Chromium 的可测性设计的效果,笔者可以给一个简单的数据:
由于笔者在工作中也从事浏览器相关的测试工作,以工作中的 Android 平台内核渲染性能测试为例:
刚开始的时候,由于不了解 Chromium 在可测试性设计上的内容(可视作没有作可测试性设计),由于在线页面的渲染测试的数据波动性较大,为了获得稳定的性能数据,一轮测试需要耗时 4 小时;
使用了 Chromium 的 Telemetry 平台之后(可视为已经完成了可测试性设计),相同规模的测试在 Telemetry 耗时仅 0.5 小时。
上面的数据是笔者在工作中实际统计的数据,那么 Chromium 以及 Telemetry 究竟在可测试性做了哪些工作,可以使得测试效率有接近 8 倍的提升呢? 这就是本文接下来要尝试分析的内容。
可测试性设计包含哪些内容
由于可测试性设计是一个相当务虚,又相当有效的话题。所以我们有必要在正式展开这个话题之前看看,软件的可测试性设计包含哪些方面的内容:
PS: 下述内容整理自 《软件可测试性设计》 一文,为了便于理解,修改了部分用词:
- 1.可操作性:“运行得越稳定,被测试的效率越高。”
- 2.可观察性:“你所看见的就是你所测试的。”
- 3.可控制性:“对软件的控制越好,测试越能够被自动执行与优化。”
- 4.可分解性:“通过控制测试范围,能够更快地分解问题,执行更灵巧的再测试。”
- 5.简单性:“需要测试的内容越少,测试的速度越快。”
- 6.低变更性:“改变越少,对测试的破坏越小。”
- 7.易理解性:“得到的信息越多,进行的测试越灵巧。”
其实上述 7 个方面都十分重要。但是由于 Chromium 以及背后的 webkit 以及 blink 是事实上的行业标准。因此,在以下 3 个方面所做的工作是显而易见的:
- 可操作性:“运行得越稳定,被测试的效率越高。”
- 低变更性:“改变越少,对测试的破坏越小。”
- 易理解性:“得到的信息越多,进行的测试越灵巧。”
因此,我们需要重点关注的就是 Chromium 以及 Telemetry 在剩下的几个方面为可测试性做了哪些工作:
- 可观察性:“你所看见的就是你所测试的。”
- 可控制性:“对软件的控制越好,测试越能够被自动执行与优化。”
- 可分解性:“通过控制测试范围,能够更快地分解问题,执行更灵巧的再测试。”
- 简单性:“需要测试的内容越少,测试的速度越快。”
Chromium 以及 Telemetry 为可测试性做了哪些工作?
那么,Chromium 团队在上述这几个方面是怎么做的呢?我们接下来一一拆解。
可观察性——The Trace Event Profiling Tool (about:tracing)
众所周知,测试是要以数据来说话的。因此,可测试性设计中尤为重要的就是被测对象能够具备良好的可观察性。对于 Chromium 项目而言,其可观察性的能力主要由 The Trace Event Profiling Tool (about:tracing) 工具来提供。为了方便,下面均简称 Tracing 工具。
关于 Tracing 工具,我们先给出 Google 对于这个工具的定义:
When diagnosing performance problems it can be valuable to see what Chrome is doing "under the hood." One way to get a more detailed view into what's going on is to use the about:tracing tool.
对于 Tracing 工具的具体能力,简要来说就是,它记录了 Chromium 中各进程以及各线程中每个方法的活动情况,既包含由 C++ 实现的内核调用情况,也包含由 JavaScript 实现的页面调用情况。
此外,Tracing 提供了一个很重要的能力——支持自定义加入Tracing。具体可以参考:Adding Traces to Chromium/WebKit/Javascript。
正是如此,Telemetry 所用的基础数据主要来源于 Tracing,相较于我们从系统或者其他三方APP获取数据,Tracing的数据无疑可以包含更多的细节而且可信度更高。
可控制性——Remote Debugging Protocol
《持续交付——发布可靠软件的系统方法》中给出了一个它所推荐的自动化验收测试的层次:
- 验收条件:支持以“假如/当/那么”的形式将验收条件写入测试中
- 测试实现层:代码使用领域语言,不引用UI元素
- 应用程序驱动层:理解如何与应用程序进行交互,来执行一系列动作,并返回结果
而要实现这种具备高可维护性特征的设计,对应用程序驱动层要求很高。特别是类似 Telemetry 这样要求在 GUI 层面上执行测试,一般而言应用程序驱动层的实现代价很大。
再次引用《持续交付——发布可靠软件的系统方法》的原话:
假如应用程序设计得比较好,GUI 层仅是清晰定义用于数据展现的代码,不包括任何业务逻辑。在这种情况下,绕过界面,基于界面下的代码进行测试的风险会相对小一些。将可测试性铭记于心,写出来的应用程序就会有一个 API,使 GUI 和测试用具(test harness)都可以用它来驱动应用程序。
Chromium 项目也实现了这么一个 API,就是 Remote Debugging Protocol。
简单来说,Remote Debugging Protocol 就是用来与浏览器页面交互和调试的协议通道。它采用 websocket 来与页面建立通信通道,由发送给页面的 commands 和它所产生的 events 组成。chrome 的开发者工具是这个协议主要的使用者,第三方开发者也可以调用这个协议来与页面交互调试。
Remote Debugging Protocol 分为不同的功能模块域:
- Console
- DOM Debugger
- Page
- Debugger
- Input
- Runtime
- DOM
- Network
- Timeline
上述模块几乎涵盖浏览器的所有操作,由于 Remote Debugging Protocol 调用浏览器的方式完成操作与 UI 操作实现原理一致。因此对于驱动层的实现帮助极大。
也正是通过 Remote Debugging Protocol, Telemetry 可以更精确的操控 Chromium,而不受系统输入系统的影响。而这对于 GUI 性能测试而言意义重大,也是文章开头所举例子中的测试效率提升的关键所在。
可分解性——Run Chromium with flags
一个使用的功能肯定是由许许多多的功能模块组成的,但是在测试的过程我们需要拥有灵活的能力去操作这些功能模块,以便于我们更加灵活的设计我们的测试方案。
举个简单的例子,Chromium 同时具备软件渲染(software rasterization)以及硬件渲染(GPU rasterization)的能力,而且默认使用硬件渲染(GPU rasterization)。当我们需要重点关注软件渲染(software rasterization)的性能时。我们需要 Chromium 具备一种便于我们更改这种默认设置,以便单独针对该模块实现测试。
于是 Chromium 为我们开放了 Run Chromium with flags 的能力。
There are command line flags (or "switches") that Chromium (and Chrome) accept in order to enable particular features or modify otherwise default functionality.
Current switches may be found at http://peter.sh/examples/?/chromium-switches.html
得益于 Run Chromium with flags 所提供的可分解性设计,Telemetry 才功能通过传入不同的启动参数的方式实现不同的测试需求。我们不敢相信,如果这些特殊功能的测试都需要开发单独打包才能实现的话,这是怎样一种坑爹的场景。
简单性——产品简单才是一切的核心
最后一点,其实说起来应该也不完全时可测试性设计所需要关注的内容。当一个产品本身很复杂时,是不可能从根本上设计出一种简单的测试方案的。因此,要想测试变得优雅,首先产品必须得优雅。
至于 Chromium 项目为我们展示的就是这种优雅,几乎只提供核心能力:页面浏览。
得益于产品的定位,Telemetry 才可以仅关注“浏览页面时“的性能数据。从而逐步封装,给出这样的框架下面框架设计。
我们不妨设想一下,如果 Chromium 包含诸如软件管理,系统清理,新闻推送等其他功能时,Telemetry 能否给出上述的测试框架设计?
我们可以从 Google 身上学到的
所实话,上述工作大部分都属于 SDET(Software Development Engineer in Test) 的职责范畴,如果所在公司的相关岗位只有 STE(Software Test Engineer) 的话,那么这个 STE 在上述事情参与程度可能不会太多。
但是,无论如何,明白“如何让产品变得优雅,让测试变得优雅”是非常重要的事情。况且梦想还是要有的,万一实现了呢。