突破测试瓶颈:Playwright网络拦截与Mock实战指南

突破测试瓶颈:Playwright网络拦截与Mock实战指南

【免费下载链接】playwright microsoft/playwright: 是微软推出的一款自动化测试工具,支持多个浏览器和平台。适合对 Web 自动化测试、端到端测试以及对多个浏览器进行测试的开发者。 【免费下载链接】playwright 项目地址: https://gitcode.com/GitHub_Trending/pl/playwright

你是否还在为API依赖不稳定导致测试失败而烦恼?是否因第三方服务限制无法模拟异常场景?本文将带你掌握Playwright的网络请求拦截技术,从基础拦截到高级Mock策略,让前端测试彻底摆脱外部依赖,实现毫秒级响应和100%可重复的测试环境。

网络拦截核心原理与基础操作

Playwright的网络拦截功能基于DevTools协议实现,允许在浏览器级别拦截、修改和模拟所有HTTP(S)请求。与传统测试工具相比,其优势在于:支持所有现代浏览器、可拦截WebSockets、API设计直观且支持多语言绑定。

基础拦截三要素

  1. 路由匹配:通过URL模式精确定位需要拦截的请求
  2. 拦截处理:决定如何响应拦截到的请求(模拟/修改/放行)
  3. 作用域控制:可针对页面、浏览器上下文或全局生效

快速上手:拦截并中止图片请求

// 阻止所有图片加载以提高测试速度
await page.route('**/*.{png,jpg,jpeg}', route => route.abort());
await page.goto('https://example.com');

官方API文档:docs/src/network.md

五种实战拦截策略

1. 完全模拟响应(无后端测试)

适用于:前端开发早期、API尚未就绪、需要隔离前端测试场景。

test("模拟用户登录成功响应", async ({ page }) => {
  // 拦截登录API请求
  await page.route('**/api/login', async route => {
    // 返回模拟的成功响应
    await route.fulfill({
      status: 200,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ 
        token: 'mock-token-123', 
        user: { id: 1, name: '测试用户' } 
      })
    });
  });
  
  await page.goto('/login');
  await page.fill('input[name="username"]', 'test');
  await page.fill('input[name="password"]', 'test');
  await page.click('button[type="submit"]');
  
  // 验证登录成功后的UI状态
  await expect(page.locator('.user-name')).toContainText('测试用户');
});

模拟响应示例:docs/src/mock.md

2. 修改真实响应(部分Mock)

当需要真实API的大部分数据,但需调整部分内容时使用,例如模拟特定用户数据或边界情况。

test("修改商品列表价格", async ({ page }) => {
  await page.route('**/api/products', async route => {
    // 先获取真实API响应
    const response = await route.fetch();
    const products = await response.json();
    
    // 修改价格数据
    const discountedProducts = products.map(product => ({
      ...product,
      price: product.price * 0.8 // 打八折
    }));
    
    // 返回修改后的响应
    await route.fulfill({
      response, // 保留原始响应的状态码和 headers
      body: JSON.stringify(discountedProducts)
    });
  });
  
  await page.goto('/products');
  // 验证价格已更新
  await expect(page.locator('.product-price').first()).toContainText('¥80');
});

3. HAR文件录制与回放

HAR(HTTP Archive)文件可录制一次网络请求,之后重复使用,特别适合:

  • 测试环境不稳定的API
  • 需要频繁重复相同请求序列
  • 离线测试场景
录制HAR文件
test('录制产品列表API请求', async ({ page }) => {
  // 录制API请求到HAR文件
  await page.routeFromHAR('./hars/products.har', {
    url: '**/api/products',
    update: true // 首次录制设为true,后续回放设为false
  });
  
  await page.goto('/products');
  // 执行操作以触发API请求...
});
修改HAR文件

录制后可直接编辑HAR文件修改响应内容:

// hars/products.har 片段
[
  {
    "name": "无线耳机",
    "price": 999,
    "inStock": true
  },
  {
    "name": "测试专用商品", // 添加自定义测试数据
    "price": 0,
    "inStock": true
  }
]
使用HAR文件回放
test('使用HAR文件测试商品展示', async ({ page }) => {
  // 使用录制的HAR文件响应请求
  await page.routeFromHAR('./hars/products.har', {
    url: '**/api/products',
    update: false // 禁用更新,使用HAR文件数据
  });
  
  await page.goto('/products');
  // 验证HAR文件中的测试商品是否显示
  await expect(page.getByText('测试专用商品')).toBeVisible();
});

HAR录制完整指南:docs/src/mock.md

4. 请求监控与断言

无需修改请求,仅记录网络交互并验证请求是否符合预期:

test("验证搜索请求参数", async ({ page }) => {
  // 监听所有API请求
  const searchRequests = [];
  page.on('request', request => {
    if (request.url().includes('/api/search')) {
      searchRequests.push(request);
    }
  });
  
  await page.goto('/search');
  await page.fill('input[name="query"]', 'playwright');
  await page.click('button[type="submit"]');
  
  // 断言请求数量
  expect(searchRequests.length).toBe(1);
  
  // 断言请求参数
  const searchRequest = searchRequests[0];
  const queryParams = new URLSearchParams(searchRequest.url().split('?')[1]);
  expect(queryParams.get('q')).toBe('playwright');
  expect(queryParams.get('page')).toBe('1');
  expect(queryParams.get('limit')).toBe('20');
});

5. WebSocket模拟

现代应用广泛使用WebSocket进行实时通信,Playwright提供完整的WebSocket拦截能力:

test("模拟实时通知", async ({ page }) => {
  // 拦截WebSocket连接
  await page.routeWebSocket('wss://example.com/notifications', ws => {
    console.log('WebSocket连接已拦截');
    
    // 监听客户端发送的消息
    ws.onMessage(message => {
      console.log('客户端发送:', message);
      // 回应客户端
      if (message.includes('subscribe')) {
        ws.send(JSON.stringify({ 
          type: 'notification', 
          content: '这是一条模拟的实时通知' 
        }));
      }
    });
  });
  
  await page.goto('/dashboard');
  // 验证是否收到模拟通知
  await expect(page.locator('.notification')).toContainText('模拟的实时通知');
});

WebSocket模拟详情:docs/src/mock.md

高级技巧与最佳实践

按环境切换Mock策略

test.beforeEach(async ({ page, context }, testInfo) => {
  // 根据测试环境决定是否使用Mock
  if (testInfo.project.name === 'mock') {
    // 注册所有必要的Mock路由
    await registerAllMockRoutes(context);
  } else if (testInfo.project.name === 'staging') {
    // 仅修改部分请求
    await registerPartialMocks(context);
  }
  // 生产环境不使用任何Mock
});

处理动态URL与鉴权

使用正则表达式匹配动态URL,并添加认证头:

// 匹配版本号动态变化的API
await page.route(/\/api\/v\d+\/user/, async route => {
  // 添加认证头
  const headers = {
    ...route.request().headers(),
    'Authorization': 'Bearer ' + process.env.TEST_TOKEN
  };
  await route.continue({ headers });
});

常见问题解决方案

问题场景解决方案参考文档
跨域请求拦截失败在浏览器上下文设置ignoreHTTPSErrors: truedocs/src/network.md
ServiceWorker干扰禁用ServiceWorker: { serviceWorkers: 'block' }docs/src/network.md
复杂请求匹配使用自定义谓词函数进行匹配docs/src/network.md

性能优化建议

  1. 作用域最小化:优先使用page.route而非browserContext.route
  2. 精确URL匹配:避免使用过于宽泛的匹配模式
  3. 并行处理:复杂响应处理使用Promise.all提高效率
  4. 复用Mock数据:将常用Mock数据抽象为可复用模块

总结与扩展应用

通过Playwright的网络拦截功能,我们不仅解决了测试环境依赖问题,还获得了:

  • 故障注入:模拟API超时、500错误等异常场景
  • 性能测试:模拟慢速网络和大延迟环境
  • 安全测试:修改请求参数测试接口安全性
  • 用户行为分析:记录用户会话中的所有网络交互

官方高级网络指南:docs/src/network.md

掌握这些技术后,你可以构建更健壮、更快速且不受外部环境影响的测试套件。尝试将这些方法应用到你的CI/CD流程中,体验真正的端到端测试自动化!

下一步行动

  1. 尝试用HAR文件录制并回放你的核心用户流程
  2. 为一个API实现完整的异常场景测试(404、500、超时)
  3. 使用WebSocket模拟构建实时功能测试

祝你测试愉快!

【免费下载链接】playwright microsoft/playwright: 是微软推出的一款自动化测试工具,支持多个浏览器和平台。适合对 Web 自动化测试、端到端测试以及对多个浏览器进行测试的开发者。 【免费下载链接】playwright 项目地址: https://gitcode.com/GitHub_Trending/pl/playwright

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值