Playwright 官方推荐的 Fixture 模式,为什么大厂架构师却在偷偷弃用?

在自动化测试圈,Playwright 的出现几乎是降维打击。而其官方文档最引以为傲的特性,莫过于 Fixtures(固件)。 官方告诉我们:*“忘掉那些手动初始化 Page Object 的繁琐代码吧,把它交给 Fixture,你会得到最优雅的依赖注入。” 初看确实如此。但当你进入腾讯、阿里或字节跳动等大厂的复杂业务线,面对 1000+ 页面对象、5000+ 测试用例** 的超大型项目时,你会发现,当初觉得“优雅”的 Fixture,正在悄悄变成项目的“维护噩梦”。 为什么很多架构师在后期选择了回归“懒加载(Lazy Approach)”?这篇文章带你拆解其中的工程化真相。

发布于 2026/03/13 10:32

SpreadJS

image

01. 引言:被“神化”的 Fixture

在自动化测试圈,Playwright 的出现几乎是降维打击。而其官方文档最引以为傲的特性,莫过于 Fixtures(固件)


官方告诉我们:“忘掉那些手动初始化 Page Object 的繁琐代码吧,把它交给 Fixture,你会得到最优雅的依赖注入。”


初看确实如此。但当你进入腾讯、阿里或字节跳动等大厂的复杂业务线,面对 1000+ 页面对象、5000+ 测试用例 的超大型项目时,你会发现,当初觉得“优雅”的 Fixture,正在悄悄变成项目的“维护噩梦”。


为什么很多架构师在后期选择了回归“懒加载(Lazy Approach)”?这篇文章带你拆解其中的工程化真相。

02. Fixture 模式:优雅的代价是“黑盒”

首先,我们必须承认 Fixture 的强大。它本质上是一种依赖注入(Dependency Injection)

// 官方推崇的模式:声明式注入
export const test = base.extend({
  userPage: async ({ page }, use) => {
    await use(new UserPage(page));
  },
  orderPage: async ({ page }, use) => {
    await use(new OrderPage(page));
  },
});

// 在用例中使用:看起来非常干净
test('下单流程', async ({ userPage, orderPage }) => {
  await userPage.login();
  await orderPage.create();
});

为什么它受宠?

  • 代码脱水:测试脚本里没有一句多余的 new

  • 生命周期自动闭环:Fixture 可以在 use() 之后自动执行清理逻辑。

为什么大厂架构师开始皱眉?

当项目规模爆炸时,Fixture 会带来 “注册表膨胀”

  1. 难以追踪的来源:当你解构出 10 个 Fixture 时,你想跳转到某个 Page Object 的定义,IDE 有时会迷失在复杂的 extend 链条中。

  2. 强制性的初始化逻辑:即便 Playwright 声明是按需加载,但在大型工程中,Fixture 之间的层层嵌套依赖,常会导致为了用一个 A,被迫触发了 B 和 C 的 Setup,增加了不必要的隐性复杂度。

03. 懒加载模式:回归“显式”的力量

懒加载(Lazy Approach)主张:只有在用到 Page Object 的那一刻,才去实例化它。

// 架构师偏爱的模式:显式实例化
test('下单流程', async ({ page }) => {
  const userPage = new UserPage(page);
  await userPage.login();

  // 只有登录成功,才加载订单页
  const orderPage = new OrderPage(page);
  await orderPage.create();
});

为什么它在大型项目中更稳健?

  1. 完美的类型推导new UserPage(page) 是标准的 TypeScript 行为,IDE 的跳转、重构、属性提示永远是秒回,不会因为复杂的类型注入而“卡死”。

  2. 零副作用:没有隐藏的 extend,没有复杂的配置文件。每个用例用到了什么、初始化了什么,一目了然。

  3. 条件分支友好:如果你的测试逻辑中有一个 if (discountAvailable),懒加载可以让你只在条件成立时才初始化“优惠券页面”对象,节省内存和潜在的初始化耗时。

04. 深度对比:工程化视角的博弈

维度

Fixture (依赖注入)

Lazy Approach (显式初始化)

可读性

极高(脚本像自然语言)

中(可见初始化代码)

可维护性

随规模增长迅速下降

随规模增长保持线性

IDE 支持

偶尔失效,跳转复杂

完美支持,原生体验

依赖关系

隐式(在配置文件里)

显式(在测试用例里)

上手门槛

需要理解 Playwright 注入机制

只要会写 PO 类即可

05. 进阶方案:架构师的“秘密武器” —— Container 模式

如果既想要 Fixture 的简洁,又想要懒加载的稳健,大厂架构师通常会封装一个 Page 容器App 对象

代码实现:

// 这是一个“页面工厂”容器
export class App {
  constructor(private readonly page: Page) {}

  // 使用 Getter 实现真正的懒加载
  get loginPage() { return new LoginPage(this.page); }
  get cartPage() { return new CartPage(this.page); }
  get paymentPage() { return new PaymentPage(this.page); }
}

// 在 Fixture 中只注入这一个 App 容器
export const test = base.extend<{ app: App }>({
  app: async ({ page }, use) => {
    await use(new App(page));
  },
});

// 最终的用例:兼顾简洁与控制感
test('完整购物流', async ({ app }) => {
  await app.loginPage.goto();
  await app.cartPage.addItem('MacBook');
  await app.paymentPage.pay();
});

这种模式的妙处在于:

  • 收拢入口:所有的页面对象都在 App 类里管理,不再有零散的 Fixture。

  • 按需实例化:只有当你访问 app.cartPage 时,对象才会被创建。

  • IDE 极其友好:输入 app.,所有的页面对象都会自动弹出,支持一键跳转。

06. 总结:你该如何选择?

官方推荐 Fixture,是因为它在演示和中小型项目中能提供极致的“代码美感”。 但在大厂的生产环境中,“稳定”和“可维护性” 永远高于“美感”。

  • 如果你的项目页面少于 50 个,且成员对 Playwright 非常熟悉,坚持使用 Fixture,它很快。

  • 如果你正在构建一个企业级测试平台,或者团队中有大量初中级开发者,请优先考虑懒加载或 App 容器模式

    • 记住: 优秀的架构不是用最炫的特性,而是用最简单、最透明的方式解决最复杂的问题。

SpreadJS | 下载试用

纯前端表格控件SpreadJS,兼容 450 种以上的 Excel 公式,具备“高性能、跨平台、与 Excel 高度兼容”的产品特性,备受华为、苏宁易购、天弘基金等行业龙头企业的青睐,并被中国软件行业协会认定为“中国优秀软件产品”。SpreadJS 可为用户提供类 Excel 的功能,满足表格文档协同编辑、 数据填报、 类 Excel 报表设计等业务场景需求,极大的降低企业研发成本和项目交付风险。

如下资源列表,可以为您评估产品提供帮助:

相关产品
推荐相关案例
推荐相关资源
关注微信
葡萄城社区二维码

关注“葡萄城社区”

加微信获取技术资讯

加微信获取技术资讯

想了解更多信息,请联系我们, 随时掌握技术资源和产品动态