Playwright测试中对象池模式的实战解析

2025-05-11   出处: medium  作/译者:Yevhenii Otsevych/溜的一比

对象池模式(Object Pool Pattern)

对象池模式是一种创建型设计模式,它维护一组预先初始化的对象——称为“池”——以供使用,而不是按需创建和销毁它们。它通过四个简单的步骤工作:

  1. 初始化池:创建并加载对象到池中。
  2. 查找合适的对象:根据特定条件选择一个可用的对象。
  3. 获取对象:将该对象保留供独占使用。
  4. 释放对象:在使用后将对象归还到池中。

为什么使用对象池模式?

主要优势是高效的资源管理和并行化协同,特别是在运行并行测试时。它还能解决一些常见问题:

  • 会话冲突:防止多个测试使用相同的会话。
  • 资源耗尽:确保用户/账户不会被过度使用。
  • 杀虫剂悖论:通过刷新对象避免陈旧的测试数据。
  • 数据发酵:确保旧数据在系统更新后仍然有效。

最佳使用场景: 当您有有限数量的对象(如测试账户),无法在测试执行期间动态生成时。

替代方法(以及为何失败)

没有对象池的情况下,常见的变通方法包括:

  • 每个测试分配:在每个测试的“Arrange”部分分配用户。
  • 套件级分配:在 @beforeAll​ 钩子中分配用户。

这两种方法都会引入测试依赖性,需要严格的执行顺序以避免冲突。这种手动操作可能导致性能下降,即使测试被均匀地重新分配到不同的套件中。

例如,如果一个套件有 20 个测试,另一个套件有 50 个测试,并行执行时,较小的套件完成后会有一条线程空闲。重新分配测试有所帮助,但并不具有可扩展性。

为什么对象池模式胜出

对象池可以保证:

  1. 每次测试只能获取一个用户。
  2. 测试独立运行,互不冲突。
  3. 当工作线程数等于池大小时,性能保持最优。

然而,当多个工作线程同时访问池时,可能会出现竞争条件。常见的解决方案包括互斥锁(mutexes)、信号量(semaphores)和线程安全结构,但 JavaScript 的单线程特性使问题复杂化。

在 Playwright 中实现对象池

Playwright Test 为每个工作线程提供了一个隔离的环境,没有共享状态。预加载用户会创建私有池,而互斥锁无法跨工作线程同步。以下是几种实现方式:

  1. 锁文件方法:当获取用户时创建一个锁文件(例如 users_copy.json.lock​)。这种方法可以防止冲突,但可能引入 I/O 开销。
  2. API 服务器(最佳解决方案) :一个集中式的 API 管理池,确保所有工作线程之间的同步。我喜欢这种方法,因为它提供了以下优势:

    • 所有工作线程的单一真实来源。
    • 内置同步机制,防止竞争条件(需要自行实现同步)。
    • 使用现代后端框架易于实现。

事实上,您至少需要两个 API 端点:

  • /acquire​ —— 预留对象。
  • /release​ —— 使用后归还对象。

此外,Playwright 的内置 webServer​ 可以在每次测试运行前启动此 API。

                        playwright webServer示例

CI 挑战与水平扩展

直到我们引入水平扩展(即在多台机器上运行 Playwright 测试)之前,这两种解决方案都表现良好。每台机器都会创建自己的私有池,使得同步变得不可能。

锁文件方法在此情况下失效,因为锁文件仅限于每台本地机器。为了克服这个问题,我们可以调整设置:

  1. 将 API 服务器作为单独的步骤运行:在运行 Playwright 测试之前,通过在 .yaml​ 文件中添加一个步骤来启动 API 服务器。
  2. 网络可访问性(前提条件) :确保所有机器都能访问部署 API 的服务器。

                                               github action .yaml示例

这种方法在所有机器之间集中管理池,确保无缝的用户管理,并防止水平扩展时的竞争条件。

结论

这是我实现的 API 服务器,以及其他提到的方法:https://github.com/eotsevych/pw-object-pool.git
我在运行测试前启动这个服务器,您可以轻松将其复用于您的目的。

提示:如果您想引入新属性或修改对象结构,请不要忘记更新对象接口(我的是 User​)。

对于 /acquire​ 端点,我传递了用户的角色和 workerId​,以便跟踪哪个工作线程获取和释放了每个用户。


声明:本文为本站编辑转载,文章版权归原作者所有。文章内容为作者个人观点,本站只提供转载参考(依行业惯例严格标明出处和作译者),目的在于传递更多专业信息,普惠测试相关从业者,开源分享,推动行业交流和进步。 如涉及作品内容、版权和其它问题,请原作者及时与本站联系(QQ:1017718740),我们将第一时间进行处理。本站拥有对此声明的最终解释权!欢迎大家通过新浪微博(@测试窝)或微信公众号(测试窝)关注我们,与我们的编辑和其他窝友交流。
27° /276 人阅读/0 条评论 发表评论

登录 后发表评论
最新文章