生命周期与并发
项目生命周期
setup、fileSetup 与 beforeAll
三者按 setup → fileSetup → beforeAll → 用例 的顺序依次执行,未配置的环节会自动跳过:
例如,当一个执行项目包含两份 YAML 文件时,setup 只会执行 1 次,而 fileSetup 和 beforeAll 会各执行 2 次(开启并发不会改变它们的执行次数)。
fileSetup 只需在项目配置中声明一次,即可自动作用于该项目下的所有 YAML 文件;而 beforeAll 则由各 YAML 文件按需声明。虽然自定义 Node 也可以在 beforeAll 中创建资源并写入 context,但框架不会为 beforeAll 自动隔离出独立的文件级 context(若未配置 fileSetup,该项目下的所有文件仍会共用 setup 返回的同一个 context 对象)。
YAML 中的生命周期钩子
生命周期钩子用于在用例执行前后准备环境、重置状态或清理数据。四个钩子均为可选配置,与 cases 处于同一层级,内部步骤的写法与用例 steps 完全相同:
在下面的 Web 示例中,每条用例开始前都会打开商城首页,结束后清除 Cookie。其中 data.prepare 和 data.cleanup 是团队自行实现并注册的自定义 Node,分别用于准备和清理测试商品;gotoUrl、clearCookies、aiAct 和 aiAssert 则是 Web 脚手架默认注册的官方 Node:
项目、文件与用例的生命周期
通过 CLI 或 runTestProject() 运行测试时,每个执行项目都拥有完整的独立生命周期。下图展示了一个包含两份 YAML 文件的执行项目在串行模式下的完整执行顺序(未声明的 YAML 钩子会自动跳过):
其中,beforeAll 和 afterAll 在每份 YAML 文件中各执行一次;beforeEach 和 afterEach 则包裹每条用例的每一次执行尝试(attempt)。开启文件并发后,不同文件可以并行推进,但单个文件内部依然严格遵循上述顺序。
当某条用例触发失败重试时,会直接复用当前文件的运行环境,仅重新执行 beforeEach → steps → afterEach → 本次尝试注册的 Node 清理,而不会重新运行项目级 setup、fileSetup 或 beforeAll。关于触发重试的条件与失败跳过规则,请参阅下文失败时如何执行。
通过 onTeardown() 注册的清理函数,其触发时机取决于注册位置:
同一作用范围内的清理函数按注册顺序的逆序(后进先出)依次执行。如果某个清理函数抛出错误,框架仍会继续执行剩余的清理函数;如果某个清理函数尚未执行完毕,后续清理函数会等待其结束。关于在自定义 Node 中注册清理函数的具体写法,请参阅资源的生命周期与清理。
context 的共享范围
Node 在 execute({ context }) 中收到的 context 取决于项目的配置方式:
在同一个共享范围内,所有 Node 接收到的都是同一个 context 对象引用——因此前一条用例写入 context.orderId 后,同一范围内的后续用例也能读到该属性。框架不会在用例切换或失败重试时自动重置 context、浏览器页面或登录状态;每条用例所需的初始状态应当在 beforeEach(或通过 onTeardown())中显式重置。
注意:请务必在 setup() 函数体内实例化资源并返回新对象。即使多个执行项目或多个文件复用了同一个 defineProjectSetup / defineFileSetup 定义,框架也会在每次初始化时分别调用 setup();但如果 setup() 直接返回模块顶层的同一个可变对象,不同项目或文件之间仍会意外共享状态。 关于跨 Node 传递数据的完整示例,请参阅跨 Node 共享上下文。
失败时如何执行
不同阶段发生错误时,框架的后续处理策略如下:
在任意阶段内部,一旦某个步骤失败,默认会跳过该阶段的剩余步骤(若配置了 continue-on-error: true,则会继续执行同阶段的后续步骤,但最终状态仍记为失败)。由于前置准备步骤可能中途失败,清理逻辑应当具备容错能力,妥善处理“资源只初始化了一半”的情况。
当某条用例执行失败时,默认会继续执行文件中的下一条用例(因此有先后依赖关系的业务步骤应当写在同一个用例中,而不应拆成多条用例)。如果配置了 test.bail

