前言:
日常开发中,如果你曾经遇到过类似问题:

  1. 一个之前开发的、很久不维护的项目或页面,突然被告知无法访问或无法使用了。
  2. 一些重数据的页面,用户反馈有的时候数据对不上,但是自己开发的时候明明测过没有问题。
    那么本文中提供的端对端测试,或许会给你解决这些问题带来一些帮助。

本文对使用 K8s 容器化运行 web 端对端测试用例进行介绍,对这个过程以及可能遇到的问题做一个整体的梳理,并且会穿插提供一定的参考资料。

相关示例代码已经开源:https://github.com/aircloud/easy-e2e

为什么我们需要端对端测试

端对端测试(也称 E2E 测试),通常是从最终用户的角度出发,模拟真实实用的场景,并验证经过一系列操作之后,用户界面的表现是否符合预期。

它比单元测试、集成测试、接口测试等更能够反映用户真实的使用情况,使用得当会对我们带来很大收益。

web 的端对端测试通常使用 Puppeteer 等工具来完成,在下文中,端对端测试即指基于 Puppeteer 的 web 端对端测试。

笔者所在的团队中,会在以下场景中使用端对端测试:

  1. 一些进入到维护阶段的项目:对于这类项目,我们没有办法继续投入测试资源,但是需要保证主流程正常,我们便可以通过定时端对端测试用例来进行每日测试并生成报告,端对端测试能够跑过即表示主流程运行正常,当每天收到“E2E测试全部通过”的报告,内心还是会多一丝安稳。
  2. 一些重逻辑的项目:各类监控统计、科学计算等平台型项目,这类项目通常会有各类计算逻辑,分散在前端、接入层和后端,甚至部分数据错误使用者也无法发现,这个时候,我们会通过端对端测试验证比如页面多处数据的一致性、数据更新时间是否及时、数据关联逻辑如累加、比例是否自洽等。

实际上,在大多项目中使用端对端测试,都会给项目带来正向的、持续的作用。

端对端测试可能面临的问题

端对端测试面临的问题主要体现在测试环境和测试用例成本两个方面。

测试环境问题

对于测试环境配置方面,在使用容器化技术之前,通常都是本地使用 Windows 或者 Mac 开发,部署使用条件受限的 Linux 开发机器。

而端对端测试通常需要有 node 环境,并且需要下载一个浏览器和对应的控制工具(如 Puppeteer),以及需要成功把浏览器运行起来。

很多时候,虽然我们本地简单安装运行成功了,但是却由于种种原因无法成功在我们的开发机运行,这一点就劝退了很多团队。

本文提供的基于 K8s 容器化的方案,能够很好地解决这一问题。

测试用例成本问题

测试用例的成本也通常是端对端测试被诟病的一点,在一些团队中,大家通常会去寻找一些“录制”测试用例的工具,并且和测试岗位的同学“协作”完成,最终通常因为录制工具不完善、工具链维护成本太高等原因,变成一个失败的 KPI 项目。

在笔者看来,如果我们已经基于 Puppeteer 开发了一个相对完整的测试骨架,并且对通用问题已经封装了通用函数(如登录态的处理),实际上在对 Puppeteer 比较熟悉的情况下,写一个测试用例的成本还是非常低的,而且我们应该主要用端对端测试对重要的用例进行编写,即可能引起 P0 事故的用例,一些特别边界的、对用户体验影响微小的测试用例由人工定期检查,这样才能做到 ROI 最高。测试用例本身也应该由研发工程师或测试开发工程师进行编写,“录制”工具仅被用于辅助我们编写用例的工具,而不能成为我们的负担。

基于 K8s 容器化运行

接下来,我们对基于 K8s 容器化运行进行介绍。

这部分我们需要一个 K8s 环境,并且在此环境内可以访问我们的目标网站,对于本地开发而言,我们可以在自己的电脑上安装一个 docker 环境进行测试。

实际上,端对端测试不会影响主业务流程,即使我们现在主业务没有使用 K8s,我们也可以独立部署一个简单环境用于端对端测试。

我们的主流程如下:

  1. 新建一个基于 Typescript 的 Node 项目,安装 Puppeteer 等依赖编写测试代码。
  2. 基于 zenika/alpine-chrome:with-node 定义一个 Dockerfile,将我们的测试代码一并打包成镜像。
  3. 本地直接通过 docker build 以及 docker container run 的方式运行镜像,进行验证(单次可能需要半分钟,不过当你开发过 Rust,你就会觉得这个时间并不算长,但能保证环境一致性)。
  4. 将完全版镜像推送到我们的内部镜像仓库,或者打成 tar 包。
  5. 利用 K8s cronjob 来设置定时任务,定时运行我们的端对端测试。

借助网上的开源项目如 alpine-chrome/with-puppeteer/,我们已经可以比较方便地来修改测试,不过笔者还是做了一些整理,放到了 easy-e2e 这个仓库,主要的一些修改如下:

  • 默认原示例是使用了 --cap-add=SYS_ADMIN 的方式来运行镜像,这种方式的问题在于,我们在部署的时候很可能由于安全策略限制被禁止这样部署(甚至还可能和运维人员扯皮),而在我们的端对端测试环境下,我们访问的网站一般都是我们自行开发的网站,相对来说可以比较信任,笔者改成了直接在代码中使用 --no-sandbox 选项,这样的好处是最小化部署的额外配置,从而更顺利地推动落地。
  • 添加了 pnpm、Typescript 的使用,对脚本做了一些整理,可以让这个示例更接近一个我们实际开发维护的项目,而不仅仅是一个 demo。

基于上文的示例仓库,我们已经完成上述 1-3 点,而镜像推送和 K8s 定时任务,实际上部署起来也非常简单,这部分由于通常需要一些认证授权配置,示例中没有给出实现。

端对端测试的一些注意事项

复杂的端对端测试通常会面临维护性问题,即我们的 dom 结构如果改变,需要修改端对端测试用例,这个没有办法完全避免,但是可以通过一些手段来尽可能地提高可维护性:

  • 对页面的主要模块增加 id,通过 id 辅助查找 dom 元素,避免出现太长的 dom 路径查询语句。
  • 在端对端测试中将 DOM 交互和查询与验证逻辑分离,验证逻辑做到和 DOM 无关。