返回知识中心
入门

面向自有测试的浏览器自动化网络 Mock

用受控的网络双替身让获准的浏览器测试保持确定性,并明确生产环境与第三方边界。

文档中心

想直接进入 入门 文档吗?

这篇文章属于博客内容库。若你要步骤化配置、参考说明和持续更新,请直接进入对应 docs 分区。

自有浏览器测试将合成请求路由到受控响应并记录有限结果

当浏览器测试同时拥有被测页面和它使用的应用依赖时,网络 Mock 很有用。受控响应可以让加载、空列表、校验错误或临时故障稳定重现,而不必等待远程服务。边界属于测试契约的一部分:Mock 是获准应用依赖的测试双替身,不是修改第三方站点、绕过策略或声称生产表现相同的方法。

先写清用户可见契约:路由、请求方法和形状、预期状态,以及测试允许保留的证据。然后决定测试拥有哪项依赖,哪项真实集成需要单独检查。可先阅读 Playwright 入门,再参考下载和上传测试指南处理生命周期与工件。Playwright API mocking 指南和 Selenium 测试实践介绍了框架机制,但合成响应不会成为远程服务的证明。

定义所有权边界

只拦截属于测试场景的请求。使用合成账户、测试 origin 和足够窄的路由模式,避免捕获分析、认证、遥测或无关资源。handler 应检查方法和相关请求字段,返回有文档的响应,并只记录简短结果。不要因为 handler 能看到就记录授权头、完整 body、Cookie、页面文本或复制的生产响应正文。

保持生产路径分离。将路由 handler 放在测试代码或仅供测试的 stub 服务中,用显式 fixture 选项启用;如果生产构建意外启用该选项,就让测试失败。结果中写出场景名称,让评审者能区分合成响应和真实集成。如果 service worker 或缓存没有让请求到达,请记录这一点。handler 没有收到请求,只能说明浏览器路径,不能证明服务被调用。

定义确定性 fixture

编写 handler 前先写下四项事实:

  • 输入: 测试拥有的合成记录、路由、方法和响应 schema。
  • 变化: 一个受控条件,例如 503 状态、空列表或有限延迟。
  • 观察: 用户可见状态和简短的匹配路由计数。
  • 清理: 删除路由、关闭 context 和工件保留状态。

只改变一个条件,失败才容易解释。如果同一 fixture 同时改变认证、重试、缓存和数据库数据,断言通过也无法说明测试了哪项契约。把响应 schema 与测试一起版本化,并使用不会被误认为客户记录的值。fixture 可以复现上游事故,但名称应明确这是合成条件。

选择最小网络 API

下面的矩阵把一个测试问题对应到一个拦截面和证据边界。每项契约使用一行,不要用一个 handler 捕获所有流量。

问题PlaywrightSelenium/WebDriver证据边界
返回已知 JSON 成功page.route('**/api/items', route => route.fulfill({ json }))driver 启动前配置的测试 proxy 或自有 stub endpoint合成响应对应的渲染状态
练习服务器错误route.fulfill({ status: 503, body: ... })stub endpoint 返回文档规定的状态错误界面和恢复操作,不是服务健康度
模拟延迟route.fulfill({ delay: 250, ... }) 或受控 stubproxy 或 stub 只延迟指定路由加载过渡和超时处理
观察但不改变流量route.continue() 加脱敏计数器只记请求元数据的 proxy 日志浏览器请求路径,不是认证成功
确保清理在 finally 中 page.unroute() 并关闭 context停止自有 proxy 并退出 driver没有 handler 或 worker 状态泄漏到下一个测试

除非测试明确验证网络策略,否则不要使用 **/* 的宽泛拦截。宽 handler 可能隐藏缺失资源,让绿色结果与真实流程无关。单一路由应检查方法、返回小 fixture,其余请求按场景契约继续或失败。意外未匹配的请求应成为可见失败,而不是被静默替换成虚构响应。

保留可重复的失败 fixture

失败 fixture 应只改变一个条件,并命名预期的用户可见结果。下面的 Playwright 示例返回合成故障,保留第一条断言错误,并始终随 context 移除 handler:

const context = await browser.newContext();
const page = await context.newPage();
let matched = 0;
await page.route('**/api/items', async route => {
  matched += 1;
  await route.fulfill({
    status: 503,
    contentType: 'application/json',
    body: JSON.stringify({ code: 'owned-test-outage' }),
  });
});
try {
  await page.goto('http://test.local/items');
  await expect(page.getByRole('alert')).toHaveText('Items are temporarily unavailable');
  expect(matched).toBe(1);
} finally {
  await page.unroute('**/api/items');
  await context.close();
}

fixture 证明页面针对该响应显示了有文档的错误和恢复路径。它不证明真实 upstream 会返回 503,不证明重试安全,不证明认证成功,也不证明远程记录没有变化。将合成代码和响应 schema 与测试放在一起。不要把生产秘密复制进 fixture。

如果 setup、断言和清理都可能失败,就保留第一条工作流错误,并把清理错误放在单独字段中。后续关闭错误不应覆盖页面失败原因。重试应创建新的 context 和新的尝试;后一次通过不能证明第一次 Mock 或真实请求没有远程影响。

决定何时需要真实依赖

Mock 是范围受限的取舍。添加 handler 前使用下面的决策表:

测试目的是否 Mock原因
验证自有页面的加载、空状态、校验或故障是确定输入能重复 UI 契约
检查序列化和支持的客户端/服务器契约通常否,使用自有集成环境Mock 检测不到 schema 或传输漂移
验证支付、身份或其他不可逆操作最终断言不使用 Mock只有获准服务能建立远程结果
在本地复现已知上游事故是,使用命名 fixture合成条件明确且可评审
探测或修改第三方服务否超出测试的所有权与授权边界

将高频 Mock 测试与少量获准真实集成结合。Mock 测试可以在每次变更运行;集成检查路由、头部、schema、授权和服务策略是否仍一致。分开它们的名称和证据,不能让合成通过掩盖真实失败。浏览器可见响应不是计费事件、账户变更、数据删除或远程可用性的证据,除非服务负责人提供相应证据。

隔离 context、数据和工件

当 Cookie、存储、权限、缓存或 service worker 会影响路由时,创建新的 BrowserContext。每个 worker 使用私有工件目录和合成标识。context 能隔离浏览器管理的状态,但不能隔离共享数据库、队列或 proxy 进程。两个测试要修改同一记录时,使用独立记录或通过应用支持的操作串行化。

把 fixture 文件和路由标签视为测试拥有的输入。只读 baseline 可以复制到 worker 目录,但部分写入结果不能替换另一个 worker 正在读取的 baseline。分开保存截图、trace 和请求计数器,并使用正常保留策略。短收据只需场景、匹配路由、响应类别、可见结果和清理状态。

清理属于 finally:删除路由,关闭页面和 context,停止自有 proxy,并把清理失败与原断言并列。如果 service worker 或缓存继续提供响应,记录观察到的路径并有意识地调整 fixture 准备。不要为了强行匹配而扩大拦截范围。

分离生产和测试流量

尽可能使用测试 hostname 或应用支持的测试模式、合成身份和独立数据存储。在 runner 配置和 CI 日志中明确显示 Mock 开关。生产构建不应导入测试 handler;生产 smoke 检查在发现测试选项时应 fail closed。这是部署边界,不只是命名习惯。

需要真实集成时,使用服务负责人批准的账户和保留策略。不要把 Mock 收据当作真实集成证明。比较同一用户可见契约,并标注哪些事实来自浏览器,哪些来自服务。如果真实路由不可用,记录外部条件,不要用合成通过替代。

BotBrowser 的能力与限制

BotBrowser 提供隔离的 BrowserContext,可用独立 cookie、存储和权限重复授权场景,但不验证远程数据库,也不保证服务端副作用。

BotBrowser 可以为获准测试提供隔离的 BrowserContext,以及分开的浏览器侧状态。当网络 fixture 需要已知 Cookie、存储、权限或干净的 service worker 状态时,这种能力很有帮助。BotBrowser 不决定测试可以拦截哪些路由,不会把第三方流量变成测试拥有的流量,也不会验证远程服务的数据库、计费、授权决定或副作用。测试负责人仍需提供合成数据、控制 handler、关闭 context,并向应用负责人索取浏览器边界之外的服务证据。

在同一份测试报告中记录能力和限制。写明 context 用途、浏览器和 framework 版本、匹配路由、响应类别、可见结果和清理收据,并说明结果来自合成依赖。Mock 通过不能证明生产可用性、授权或业务交易成功。干净的 context 也不能证明服务器会话已撤销或远程队列已清空。

合并前复核边界

检查 handler 是否只匹配一个自有路由,fixture 是否只改变一个条件,未匹配流量是否遵循有意的策略,以及 setup 和断言失败后是否仍执行清理。按应用契约需要时运行一次 Mock 成功、一次强制失败和一次获准真实集成。查看新鲜结果中的路由标签和清理收据,不要转储请求 body。

明确确认四项非声明:fixture 不修改第三方服务;响应不证明上游健康;浏览器隔离不删除服务器数据;重试不会消除第一次尝试的不确定性。这样网络证据才会保持有用、私密,并与测试的浏览器行为相称。

先确认路由所有者再选择语法。应用 URL 可能属于供应商或其他团队。写明所有者和获准环境。若所有权不清晰,把请求留在获准集成,只断言允许观察的界面行为。

认证流程也需要边界。使用测试环境的合成会话,明确获准角色,不要复制客户会话。Mock 的 401 或 403 可以检查界面,但不能证明真实策略引擎作出了相同决定。

缓存策略要有意选择。清理缓存能稳定 fixture,保留缓存能验证缓存响应。记录选择和路由是否匹配。若缓存先提供响应,保留观察结果,不要扩大路由模式。

并行运行时,每个 worker 都应有自己的 receipt、临时文件和合成记录。context 保护浏览器状态,但应用数据仍需要独立键或获准的串行化规则。

让匹配条件明确:HTTP 方法、路径和场景参数。接受所有方法的路由可能把写入变成合成响应;忽略版本的规则可能隐藏升级。小型条件更易审阅,也能显示意外请求。

响应类别属于契约。成功只包含页面需要的字段,错误遵循有文档的形状。额外字段会掩盖意外依赖,缺失字段会产生未文档化契约。

让时间可观察但不要脆弱。有限延迟可检查加载状态,断言应等待变化而不是固定 sleep。记录延迟并区分预期 timeout 与未匹配路由。

Mock 和真实集成使用同一 receipt:场景、路由、方法、类别、状态、计数和清理。不放入凭证、Cookie、完整正文或私密文本,避免混淆浏览器观察与服务事实。

重试需要独立断言。每次尝试都是新的并保留第一次结果。若第一次可能到达真实服务,记录不确定性。Mock 测试重试流程,远程副作用由获准集成确认。

让 fixture 靠近解释它的断言。命名合成条件,链接用户契约,并写明覆盖传输与服务的真实检查。

认证流程也需要明确边界。使用合成会话,定义获准角色,不要复制客户会话。Mock 的 401 或 403 可以检查界面,但不能证明真实决定。

缓存策略应明确选择。清理缓存能稳定 fixture,保留缓存能测试缓存响应。记录选择,若缓存先响应则保留观察结果。

并行运行时,每个 worker 都要有自己的 receipt、临时文件和合成记录。context 保护浏览器状态,但应用数据需要独立键或获准串行化。

来源

#浏览器自动化#网络 Mock#Playwright#测试双替身#确定性测试

让 BotBrowser 从研究走向生产

先用这些指南理解模型,再进入跨平台验证、隔离上下文和面向规模化的浏览器部署。