5月27日 23:18
Cypress 的 beforeEach、before、afterEach 和 after 钩子有什么区别?
核心区别
四个钩子的根本区别在于执行频率和作用域:
beforeEach/afterEach:每个it用例前后各执行一次,作用域为当前describe块内所有用例before/after:整个describe块开始前和结束后各执行一次,作用域为整个测试套件
| 钩子 | 执行时机 | 执行次数 | 典型用途 |
|---|---|---|---|
beforeEach | 每个 it 之前 | N 次(N = 用例数) | 重置状态、登录、访问页面 |
afterEach | 每个 it 之后 | N 次 | 清除 cookie、会话、快照 |
before | 所有 it 之前 | 1 次 | 种子数据、全局配置 |
after | 所有 it 之后 | 1 次 | 数据库清理、资源释放 |
执行顺序
嵌套 describe 时,钩子的执行顺序遵循"从外到内"原则:
javascriptdescribe("外层", () => { before(() => cy.log("outer before")); // 1 beforeEach(() => cy.log("outer beforeEach")); // 3, 7 describe("内层", () => { before(() => cy.log("inner before")); // 2 beforeEach(() => cy.log("inner beforeEach")); // 4, 8 it("测试A", () => cy.log("test A")); // 5 it("测试B", () => cy.log("test B")); // 9 afterEach(() => cy.log("inner afterEach")); // 6, 10 }); afterEach(() => cy.log("outer afterEach")); // 最后执行 });
输出:outer before → inner before → (outer beforeEach → inner beforeEach → 测试A → inner afterEach → outer afterEach) × 2轮
选择依据
- 需要每个用例都从干净状态开始 →
beforeEach,不要用before - 用例之间允许共享状态(如只读数据) →
before一次性初始化 afterEach适合清理当前用例产生的副作用(如 localStorage)after适合清理整个套件的资源(如测试数据库)
常见错误:在 before 中登录,然后所有用例共享登录态。一旦某个用例意外注销,后续用例全部失败。正确做法是用 beforeEach 登录,保证每个用例的独立性。
追问
Q: beforeEach 中 cy.visit() 和 cy.request() 有什么区别?
cy.visit() 会加载完整页面并等待页面事件,较慢;cy.request() 只发 HTTP 请求不渲染,适合用 API 预设数据来加速测试。
Q: 钩子中的断言失败会影响用例执行吗?
会。beforeEach 中断言失败,该用例跳过;afterEach 中失败会标记用例为失败,但不影响下一个用例的执行。
Q: 为什么 Cypress 官方更推荐 beforeEach 而非 before?
因为 Cypress 的核心原则是测试隔离。before 共享状态容易导致用例间耦合,一个用例的副作用会污染后续用例。beforeEach 保证每个用例从相同初始状态运行,测试更稳定。