软件测试 | K&S 批量运行测试用例
通过前面文章已经了解了 K8S 大概的运行机制,接下来看一下在测试领域中如何用 K8S 来高效的 解决分布式运行测试用例的场景。 在企业中运行 UI 自动化与学习中是不一样的,最大的不同之处就在 于企业的场景中测试用例的量级非常的恐怖, 通常一款超过 2 年的 TO B 类型的产品都会拥有数以千 计的 UI 自动化测试用例。 这个时候测试的运行效率会成为最大的瓶颈。 在这个时候企业会寻求并发 执行测试用例的能力。 一般每种语言的测试框架都会提供相应的并发测试机制, 但是这种机制通常都 是单机的并发能力,而这种并发模型都会存在单机的性能瓶颈, 无法在一台服务器中启动太多的浏览器 执行测试。 所以在测试用例的规模达到一定量级后,寻求多机的分布式执行测试的能力成为了必须的测 试架构。 目前各种领域都提供了一些可用的分布式执行能力,这其中以 Selenium 官方团队的 Grid, 移动端的 STF 和 Cypress 的用例文件分割模式比较流行。下面来介绍一下 selenium 的 Grid 是如何在 K8S 中进行部署的。
SELENIUM GRID
Gird 的理念是将浏览器单独提取出来并进行集群化管理, 在以前测试程序和浏览器通常是绑定在一台 机器的,而 Grid 的出现把浏览器单独部署成为一个集群,而测试程序通过 remote Webdriver 来代替之 前的 Webdriver 与远程浏览器进行通信并执行测试用例。 而接收测试请求的角色就是 Grid 架构中的 Master 节点,有时候它也被称为 Hub 节点。 作为浏览器集群的 Master 节点,它主要的工作是负责接 收测试程序的请求并把测试任务平均分发到在它下面注册的多个 Node 节点上去, Node 节点作为 Gird 架构的 worker 节点,是真正启动浏览器并执行测试的地方。 所以在这套架构下需要做的事情有以下 3 点:
测试程序从之前的 Webdriver 变成 remotewebdriver 以跟 Gird 的 Master 节点通信。
在 K8S 中 1 台节点上部署 Grid 浏览器集群中的 Master 服务
在 K8S 中的多台几点上部署 Grid 浏览器集群中的 Node 服务
首先看一下如何在 K8S 集群中部署 Master 节点
上面是 Grid master 节点部署在 K8S 中的配置文件,这里又接触到了一个新的资源对象也就是 Deployment,这个对象的作用和使用方法都很容易理解。它的目的是维持 POD 的数量,在 spec 字段 下有一个非常关键的字段是 replicas,代表着 Deployment 对象要维护的 POD 的数量, 如果用户把这 个值设置为 3 那么 Deployment 会保证在 K8S 集群中一定会有这 3 个 POD 存在,如果其中任何一个 POD 出现故障,Deployment 都会创建新的 POD 来补充进去, 而创建什么样的 POD 由配置文件中的 template 字段决定,它是 POD 的模板,是指导 Deployment 创建什么样的 POD 的模板。 K8S 正是通 过 Deployment+Service 模式来完成通用的负载均衡+高可用的架构设计的:Deployment 会保证 K8S 集 群中一定有多个业务 POD 处于运行状态而 Service 在接管 POD 网络后能保证流量是通过负载均衡的机 制平均分发到每个 POD 中的。 当然在目前的场景下 replicas 设置为 1 即可。 然后再看一下作为 worker 角色的 Node 节点如何在 K8S 中进行部署:
在 Node 的配置文件中需要注意 2 点:
由于 Node 节点需要到 Master 节点上注册自己的信息,所以需要让 Node 节点知道 Master 节点 的 IP 地址。 这里是通过环境变量的形式注入到容器中的,所以需要记住这两个固定的环境变量。 同时 K8S 为了解决服务发现的问题,在集群中内部部署了 DNS 服务器,曾在 K8S 的安装章节提 到过。 而任何 Service 在创建的时候都会将自己的名字也就是 name 这个字段作为域名注册到 DNS 服务器中, 这样在 K8S 内部寻址方式统一使用域名寻址即可。 所以在 Node 的配置中指定 Master 服务的 ip 地址为 selenium-hub, 因为在创建 Master 服务的 Service 时候为 name 字段填 写值正是 selenium-hub。
在上面的配置文件中,仍然使用 Deployment 来维护 POD 的数量,replicas 字段填写的值是 6,也 就是每个 Node 服务注册 60 个浏览器(Node 服务的 NODE_MAX_INSTANCES 和 NODE_MAX_SESSION 两个环境变量填写的都是 60) 一共 360 个浏览器。 但是这种部署方式 有一个缺点是 Deployment 并不保证这 6 个 POD 是分布在不同的节点上的,也就是说可能存在两 个或多个 POD 是部署在同一台节点上导致浏览器的分布并不均匀, 失去了分布式运行的优势。所 以为了解决这个问题可以换用 Daemonset 这个资源对象来代替 Deployment,这两个资源类型很 像,目的都是在集群中维护多个 POD。Daemonset 不同的是它没有 replicas 字段,取而代之的是 它保证 K8S 集群中每个节点上都有且只有一个 POD 存在,它十分适合本次的部署场景,能够保证 每个节点上的浏览器绝对的平均分布。
部署完毕后可以通过 Master 服务暴露的端口号来访问图形界面:
如果能看到上面的图就说明部署已经成功了, 接下来只需要在测试代码中使用 remote webdriver 连接 Master 节点即可。
上面我使用 Java 的 Selenide 框架来执行自动化测试, 它封装了很多 Webdirver 的细节所以配置上更为 简单,只需要 Configuration.remote 指定好 Grid 的地址即可。
CYPRESS 的分布式执行测试用例
Cypress 作为最近两年流行起来的 UI 自动化测试框架,它在并发执行上并没有像 Selenium Grid 的设计 一样去虚拟化一个浏览器集群, 相反的它用一种非常简单的设计方式,就是把任务的调度交给用户自己 来做,用户只需要运行如下命令:
如果使用 Cypress 的数据控制 Dashboard 完成并发运行的话,那需要去官方网站注册并创建对应的 project, 在运行的时候指定 --key 和--ci-build-id $BUILD_TAG --parallel 来完成并发能力, 只要用户 在不同的机器上运行 cypress 命令的时候使用同样的 key 和--ci-build-id 那么 dashboard 就会认为他们 属于同一个测试任务将他们的测试结果整合成一个测试报告。同时想要完成 cypress 的并发测试需要将测试用例拆分成多个测试文件, 因为 Cypress 的调度粒度是控制在文件级别的, 比如用户希望有用 10 个并发的能力那就需要将测试用例拆分成 10 个文件保存,然后分别在不同的机器上运行这 10 次 命令完成这 10 个测试文件的测试。 不得不说这种分布式测试的能力比起 Selenium Grid 来说差了至少 一个等级。 这样需要用户每一次更改并发数量就对测试文件进行重新拆分,如果拆分的不够均匀还容易 造成长尾现象, 最痛苦的是用户需要自己来编写任务分发工具将测试程序调度到不同的机器上运行 Cypress 命令。 为了解决这个任务分发问题需要利用 K8S 的调度能力来完成。 常用的做法是使用 K8S 的 job 对象来将任务提交到 K8S 中运行, 由于 K8S 本身就是集群架构,有自己的负载均衡调度 策略,所以它能够保证 Cypress 的任务调度到不同的节点上分摊压力。可以利用在 K8S 容器编排介绍 的那一章中针对 job 的配置文件
如上述配置文件中编写的配置,如果希望有 10 个浏览器的并发度,那在拆分完测试文件后,只需要提 交 10 次 job 来运行 Cypress 的测试任务,通过环境变量来指定每一次测试任务需要执行哪一个测试文 件。 这样就完成了 Cypress 中最难以完成的任务分发工作了,因为 K8S 会帮将任务分发到集群上不同 的节点上去以完成任务的分布式执行。
搜索微信公众号:TestingStudio 霍格沃兹的干货都很硬核
评论