精通 Cypress 网络拦截:详细指南

发布: (2025年12月25日 GMT+8 12:30)
13 min read
原文: Dev.to

Source: Dev.to

请提供您希望翻译的正文内容,我将按照要求将其翻译成简体中文并保留原有的格式、Markdown 语法以及技术术语。

介绍

在当今竞争激烈的软件测试领域,高效处理网络请求是确保 Web 应用程序功能顺畅的关键。现代端到端测试框架 Cypress 提供了强大的拦截和测试网络请求的功能,成为测试自动化的游戏规则改变者。

本文深入探讨了使用 Cypress 进行网络拦截的方方面面。从 API 请求处理的基础到高级存根技术以及响应验证,指南涵盖了你需要了解的全部内容。它展示了 Cypress 如何赋予测试人员模拟边缘情况、调试复杂交互并获得更高测试覆盖率的能力。阅读完本文后,你将全面掌握如何将网络拦截纳入 Cypress 测试自动化策略,从而提升测试的可靠性和效率。

本博客面向希望提升自动化技能的测试人员和开发者,提供逐步说明、实用示例以及网络测试最佳实践的洞见。

什么是网络请求拦截?

网络请求拦截在自动化测试的上下文中指的是在测试会话期间对客户端和服务器之间的 HTTP 请求和响应进行监控、修改或完全存根 的过程。此功能对于依赖 API 或 Web 服务的测试场景至关重要,能够确保应用能够处理所有可能的情况——例如成功响应、服务器错误和延迟响应。

例如

  • 拦截获取用户数据的 API 调用并使用虚拟数据模拟响应,可验证应用在不依赖后端可用性的情况下如何处理不同场景。
  • 测试服务器返回 500 错误的边缘情况,可验证 UI 中的回退机制或错误信息。

网络拦截示意图

为什么网络拦截在自动化测试中至关重要?

  • 隔离应用行为 – 在不依赖实时后端服务器(可能不稳定或不可用)的情况下测试前端逻辑。
  • 模拟边缘情况 – 轻松模拟网络响应慢、服务器错误或意外负载等场景。
  • 提升测试可靠性 – 通过控制外部依赖降低不稳定性,使测试更稳定、可重复。
  • 验证 API 合约 – 确保应用发送正确的请求并按预期处理响应。
  • 简化调试 – 拦截请求和响应,以了解应用与服务器之间的通信内容。

Source:

使用 Cypress 进行 API 拦截的优势

Cypress 通过强大的 cy.intercept 命令简化了网络拦截,相比传统测试工具提供了多项优势。

易用性

Cypress 为拦截和修改网络请求提供了声明式且易读的语法。

Cypress 拦截示例

示例 – 拦截所有对 /api/usersGET 请求,并使用 users.json fixture 文件返回预定义的 JSON 响应。

// cypress/e2e/intercept-users.spec.js
cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers').its('response.statusCode').should('eq', 200);

实时调试

Cypress 内置的测试运行器实时显示拦截的请求及其详细信息,便于快速验证和排查问题。

无需中间件

不同于某些需要代理服务器或额外中间件的工具,Cypress 原生集成,省去搭建时间。

模拟复杂场景

使用 cy.intercept,可以动态模拟 API 响应,以测试分页、认证等复杂工作流。

示例 – 模拟分页

分页模拟示例

// 模拟第一页
cy.intercept('GET', '/api/items?page=1', { fixture: 'items-page-1.json' }).as('page1');
// 模拟第二页
cy.intercept('GET', '/api/items?page=2', { fixture: 'items-page-2.json' }).as('page2');

完整断言

Cypress 允许对请求、负载、头信息和响应进行断言。

示例 – 验证请求负载

负载验证示例

cy.intercept('POST', '/api/login', (req) => {
  expect(req.body).to.have.property('username', 'testuser');
  expect(req.body).to.have.property('password');
  req.reply({ fixture: 'login-success.json' });
}).as('login');

简化测试维护

fixturesaliases 等特性让你能够组织测试数据和拦截规则,实现跨多个测试的复用,使测试套件保持 DRY(不重复)并易于维护。

通过使用 Cypress 的网络请求拦截,你可以完全掌控应用的外部依赖,构建既覆盖 UI 又覆盖 API 层的稳健、全面的自动化测试。这是现代测试自动化从业者必备的技能。

Source:

Cypress 中 cy.intercept 的基础

cy.intercept 简介

cy.intercept 是 Cypress 的一个命令,用于 拦截修改 HTTP 请求与响应。它取代了旧的 cy.route API,提供了更强大、更灵活的接口。

语法概览

cy.intercept([method], url, [routeHandler])
参数类型描述
methodString(可选)要匹配的 HTTP 方法(GETPOSTPUTDELETE 等)。如果省略,则匹配任何方法。
urlString、RegExp 或 Object要匹配的 URL 模式。支持全局模式(**/api/**)或正则表达式。
routeHandlerObject 或 Function(可选)定义如何响应或修改请求。可以是静态存根、fixture,或接受请求对象的函数。

简单示例 – 存根 GET 请求

// 存根对 /api/todos 的 GET 请求并返回 fixture
cy.intercept('GET', '/api/todos', { fixture: 'todos.json' }).as('getTodos');

动态响应示例

cy.intercept('POST', '/api/login', (req) => {
  // 检查请求负载
  expect(req.body).to.have.property('username');

  // 动态决定响应内容
  if (req.body.username === 'admin') {
    req.reply({ statusCode: 200, body: { token: 'abc123' } });
  } else {
    req.reply({ statusCode: 401, body: { error: 'Invalid credentials' } });
  }
}).as('login');

使用别名进行等待

cy.wait('@login').its('response.statusCode').should('eq', 200);

使用通配符匹配

// 匹配 /api/users/* 下的任何 GET 请求
cy.intercept('GET', '/api/users/**', { fixture: 'user.json' });

修改外发请求

cy.intercept('GET', '/api/products', (req) => {
  // 在请求发送前添加自定义头部
  req.headers['x-test-header'] = 'cypress';
  req.continue(); // 继续发送(已修改)的请求
});

关键提示

  1. 在触发请求的操作之前设置拦截。
  2. 使用 as() 创建别名 – 这使得 cy.wait() 更加方便,并能对请求/响应进行断言。
  3. 利用 fixture 来复用静态数据。
  4. 结合 cy.wait() 使用,以避免因竞争条件导致的 flaky 测试。

综合示例 – 示例测试

describe('User Dashboard – Network Interception', () => {
  beforeEach(() => {
    // Stub the user list API
    cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers');

    // Stub a delayed response to test loading state
    cy.intercept('GET', '/api/notifications', (req) => {
      req.reply((res) => {
        // Simulate a 2‑second network delay
        setTimeout(() => {
          res.send({ fixture: 'notifications.json' });
        }, 2000);
      });
    }).as('getNotifications');

    cy.visit('/dashboard');
  });

  it('displays the user list from fixture', () => {
    cy.wait('@getUsers');
    cy.get('[data-cy=user-row]').should('have.length', 5); // assuming 5 users in fixture
  });

  it('shows loading spinner while notifications are delayed', () => {
    cy.get('[data-cy=notifications-spinner]').should('be.visible');
    cy.wait('@getNotifications');
    cy.get('[data-cy=notifications-spinner]').should('not.exist');
    cy.get('[data-cy=notification]').should('have.length.at.least', 1);
  });
});

最后思考

Network request interception with Cypress gives you full control over the external interactions of your application, enabling you to:

  • 编写确定性、快速且可靠的测试。
  • 模拟难以重现的边缘情况。
  • 在单一测试流程中验证 UI 行为和 API 合约。

掌握 cy.intercept 是现代测试自动化工程师的基石技能。祝测试愉快!

介绍

Cypress 6.0 引入了 cy.intercept 命令,提供了增强的功能和对测试期间网络流量的更好控制。

此强大功能可以:

  • 监控出站和入站的 HTTP 请求。
  • 存根并模拟响应。
  • 验证负载、头部和响应结构。
  • 模拟超时、服务器错误或无效数据等边缘情况。

cy.routecy.intercept 的关键区别

cy.route vs cy.intercept comparison

cy.intercept 通过允许详细的请求匹配、响应操控以及高级验证,提供了无与伦比的灵活性。

语法概览 – 基础用法

cy.intercept 命令可以根据需求的复杂程度接受不同的参数。

基础语法

基础语法图


Source:

cy.intercept 用法示例

1. 拦截 GET 请求 – 监控与验证

// Intercept GET /api/users and assign an alias
cy.intercept('GET', '/api/users').as('getUsers');

// Trigger the request in your app (e.g., click a button)
cy.get('button.fetch-users').click();

// Wait for the request and assert response
cy.wait('@getUsers').its('response.statusCode').should('eq', 200);
cy.wait('@getUsers')
  .its('response.body')
  .should('have.length.greaterThan', 0);

说明

  • 拦截指向 /api/users 的请求。
  • 为了便于引用,分配了别名 @getUsers
  • 验证返回的状态码和响应体。

2. 存根响应 – 使用 JSON 固件

// Stub GET /api/products with a fixture file
cy.intercept('GET', '/api/products', { fixture: 'products.json' }).as('getProducts');

说明

对所有指向 /api/products 的 GET 请求,都将返回 products.json 固件中的数据。


3. 动态修改响应

cy.intercept('POST', '/api/login', (req) => {
  // Simulate a login failure
  req.reply({
    statusCode: 401,
    body: { error: 'Invalid credentials' },
  });
}).as('loginFail');

说明

拦截对 /api/login 的 POST 请求,并动态覆盖响应体,以模拟登录失败的情况。


4. 模拟服务器错误(500)

cy.intercept('GET', '/api/orders', {
  statusCode: 500,
  body: { error: 'Internal Server Error' },
}).as('ordersError');

说明

模拟 500 错误,帮助你验证应用的错误处理机制。


5. 验证请求负载

cy.intercept('POST', '/api/submit', (req) => {
  // Assert payload structure and values
  expect(req.body).to.have.all.keys('name', 'email', 'message');
  expect(req.body.email).to.match(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
}).as('submitForm');

说明

  • 拦截对 /api/submit 的 POST 请求。
  • 验证负载中包含预期的键,并检查 email 的格式是否正确。

最佳实践

  • 使用别名 – 为拦截的请求分配别名 (as('myAlias')) ,以便在 cy.wait 中轻松引用。
  • 组织 Fixture – 将可复用的测试数据存放在 cypress/fixtures 文件夹中,以保持模拟响应的一致性。
  • 测试边缘情况 – 模拟延迟、超时和格式错误的响应,以确保健壮性。
  • 调试 – 利用 Cypress 的 Test Runner 实时检查拦截的请求和响应。

拦截 GET、POST、PUT 和 DELETE 请求

拦截各种 HTTP 方法对于在 Web 应用中测试不同的 API 交互至关重要。Cypress 使用 cy.intercept 可以轻松实现这一点。

示例:拦截 GET 请求

场景: 测试应用如何获取用户列表。

cy.intercept('GET', '/api/users', { fixture: 'users.json' }).as('getUsers');
cy.visit('/users');
cy.wait('@getUsers').its('response.statusCode').should('eq', 200);

示例:拦截 POST 请求

cy.intercept('POST', '/api/users', (req) => {
  // 验证请求负载
  expect(req.body).to.have.property('name');
  // 存根响应
  req.reply({ statusCode: 201, body: { id: 123, ...req.body } });
}).as('createUser');

示例:拦截 PUT 请求

cy.intercept('PUT', '/api/users/*', (req) => {
  // 动态修改响应
  req.reply({ statusCode: 200, body: { ...req.body, updatedAt: new Date().toISOString() } });
}).as('updateUser');

示例:拦截 DELETE 请求

cy.intercept('DELETE', '/api/users/*', {
  statusCode: 204,
}).as('deleteUser');

进一步阅读

阅读完整博客:
https://tinyurl.com/34wb5k66

Back to Blog

相关文章

阅读更多 »

管理多个 Playwright 项目?

已清理的 Markdown markdown !Forem Logohttps://media2.dev.to/dynamic/image/width=65,height=,fit=scale-down,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s...