7.4 Selenium 测试的高速化
之前已经多次提到,Selenium 的测试中经常会出问题的就是测试的速度。Selenium 的测试是从使用浏览器的系统用户的观点出发的集成测试,加上 Selenium 自身的速度并不快,因此和单元测试相比的确是非常耗费时间的测试。
另外,在用 Selenium IDE 制作测试用例的情况下,因为非常简单,所以往往容易不加思索地对各处进行测试,结果就导致执行所有的测试需要耗费大量的时间。
下面是笔者所在公司的 Selenium 测试套件数量的演变图(图 7.17)和所有测试套件执行时间的演变图(图 7.18)。随着自动测试的不断增加,执行所有测试甚至要花费数日之久。
图 7.17 Selenium 测试套件数量的演变
图 7.18 Selenium 测试执行时间的演变
作为上述问题的有效解决方案,本节将介绍并行执行测试的方法。
7.4.1 利用 Jenkins 的分布式构建实现测试的并行执行
首先,正如之前在“好的测试用例”一节中所讲的那样,开始并行执行测试时,各个测试套件必须不相互依赖,能够单独通过测试。在此基础上再利用 Jenkins,即可构建并行执行的机制。
Jenkins 提供了“分布式构建”这一功能强大的机制来支持并行测试。这里对基于上述机制的并行执行进行讲解。
●…… Jenkins 的分布式构建的构成
利用 Jenkins 的“分布式构建”机制能够组建从数十台到数百台机器的集群(图 7.19)。
图 7.19 Jenkins 的主(master)和从(slave)结构
各台机器根据功能的不同分为 master 和 slave 两种。安装有 Jenkins 的机器作为 master 负责各种配置信息的管理、构建时处理流程的控制,以及调度各 slave 实施处理等。
slave 从 master 接收指令,从版本管理系统上取得、更新代码或测试用例并执行测试。
●…… 分布式构建的配置
接着就让我们试着实际构建一下 Jenkins 的 master 和 slave 架构。这里以 Windows 平台为例讲解 slave 的架构。
❶ 配置 slave 机器的 Jenkins
从 Jenkins 的“系统管理”→“管理节点”→“新建节点”开始新建 slave 节点(图 7.20)。slave 的种类选择“Dumb Slave”。其他项目的设置如表 7.4 所示。
图 7.20 配置 slave 机器的 Jenkins
表 7.4 slave 的设置
| 项目 | 说明 |
|---|---|
| Name | 设置 slave 节点的名称。以 slave 的计算机名来命名简洁易懂 |
| 描述 | 设置节点的描述 |
| of executors | 设置 slave 机器上能够同时构建的任务数量。可以先设置为 3 或 5,确认执行测试时的负载后再进行调整 |
| 远程工作目录 | slave 机器上 Jenkins 的根目录。可以设置为 c:\jenkins 等 |
| 标签 | 可以为各 slave 机器标注标签。输入例如“windows”这样提示 slave 特征的标签 |
| 用法 | 指定构建的调度方法。设置为默认的“尽可能使用这个节点” |
| 启动方法 | 选择“Launch slave agents via Java Web Start” |
| Availability | 指定 slave 的可用性。设置为默认的“Keep this slave on-line as much as possible” |
❷ master 和 slave 的连接
从新添加的 Windows 节点的浏览器打开 Jenkins,点击步骤 ❶ 中创建的 slave 画面上 的“Launch” 键,就能下载 JNLP 文 件。运行该 JNLP 文件,就会安装作为 slave 节点所需要的文件,并连接 master。Windows 会因为 Windows update 而频繁地重启,因此要进行如下设置。
将下载的 JNLP 文件存放到启动目录下
设置为自动登录
❸ 配置测试任务在哪个 slave 上执行
在各任务配置的“Restrict where this project can be run”(图 7.21)中指定让哪个 slave 来执行构建处理。这里可以填入步骤 ❶ 中设置的 slave 节点名、slave 的标签,或者标签和逻辑运算符(&& 或 || 等)的组合,由符合这里设定的限制条件的 slave 节点之一来执行构建处理。可以直接在“Restrict where this project can be run”设置 slave 节点名,但这并不是聪明的方法,因为随着测试任务的增加,特定 slave 的负担加重,即使构建了分布式的环境,但因为限制了特定的 slave,也会造成无法顺利均衡负载。因此理想的方法是使用 slave 的标签。
图 7.21 配置测试任务在哪个 slave 上执行
❹ 执行构建
点击 Jenkins 任务的“立即构建”就会启动 slave 机器执行测试。这样分布式构建环境的构筑就完成了。
7.4.2 Selenium 测试并行化中的难点
至此,我们讲解了为了尽快完成测试,实现 Selenium 测试的高速化,测试用例应该符合哪些条件,以及并行执行多个测试用例的方法。
这里再介绍一下笔者所在公司并行执行测试时所发生的问题。虽然在多数系统上该问题未必会发生,但可以为解决推进 Selenium 测试并行化过程中的若干问题提供一些启示。
在之前的“使 Selenium 测试稳定运行”这一小节中,我们介绍了 Selenium 会无视当前页面内容是否加载完成,而直接继续下面的测试,因而造成了系统虽然正常运行但测试依然失败的情况。造成这种现象的原因可能是服务器正在备份或解析日志等而造成服务器的负载变高。
同样,并行执行测试也会引发新的问题,那就是并行执行会启动多个浏览器,这些浏览器的请求会集中发往特定的服务器,这样该服务器的响应就会变得缓慢。
根据上述方法并行执行 Selenium 测试的情况下,Jenkins 任务中指定的 slave 或标签就是会启动浏览器的机器。上述方法可以实现运行浏览器的机器的负载均衡,但无法实现从浏览器接收请求的服务器的负载均衡(图 7.22)。
图 7.22 Selenium 测试并行执行时的请求不均衡
这个问题虽不会造成测试失败频繁发生,但在运行系统的服务器配置较低或系统的处理能力较差等情况下就很容易造成这样的问题。
对于上述问题,我们采取的对策是将浏览器客户端和运行系统的服务器进行 1:1 配对(图 7.23),包括应用程序用到的服务器端的缓存服务器以及数据库服务器等,都和浏览器客户端组成 1 个配对,通过增加浏览器客户端和服务器端的配对形式来扩展测试的规模。
图 7.23 1∶1 的浏览器客户端和服务器的结构
要使浏览器客户端和服务器进行 1∶1 的配对,就需要替换各个机器上的 hosts 文件,使其向特定的机器发送请求(图 7.24)。例如,替换浏览器客户端机器上的 hosts 文件,使其向对应的应用程序服务器发送请求。
图 7.24 hosts 文件的修改
这样特定机器上运行的浏览器的请求就会发往特定的服务器进行处理。服务器端也一样,固定服务器上运行的应用程序会使用其对应的数据库服务器。
如上所述,使用 Selenium 进行的是集成测试,所以和单元测试的并行执行不同,浏览器端的机器、服务器端的机器或数据库服务器等,其中任意一项的高负载都会造成测试不稳定。根据具体的原因处理方法也有所不同。在推进测试的并行执行过程中,机器的负载是需要注意的问题之一。
