首页/新闻资讯/正文详情

Detox 测试生命周期完全指南:init、beforeEach/afterEach 与 cleanup 的正确用法

发布时间:2026/9/24 11:42:15 来源:云帆数科 栏目:资讯中心
Detox 测试生命周期完全指南:init、beforeEach/afterEach 与 cleanup 的正确用法
测试移动开发质量保障开发工具【免费下载链接】DetoxGray box end-to-end testing and automation framework for mobile apps项目地址https://gitcode.com/gh_mirrors/de/Detox点击查看免费下载本文以 Detox 19.x 官方文档《Test Lifecycle》为骨架系统讲解 E2E 测试运行的全生命周期管理从detox.init()初始化、每个用例前后的detox.beforeEach()/detox.afterEach()钩子到收尾阶段的detox.cleanup()并深入仓库源码DetoxPrimaryContext.js、DetoxWorker.js验证其底层实现。读完本文你将掌握在 mocha、jest 或自定义测试运行器下正确挂接 Detox 生命周期、让录屏/截图/日志等 artifacts 正常工作、并保证每个用例拥有干净一致起点的完整实战方案。概述Detox 与测试运行器无关Detox 本身不绑定任何测试运行器test runner independent。无论你使用 mocha、jest 还是 ava、tapeDetox 只负责提供一套与运行器解耦的生命周期 API由你在测试框架的钩子before/beforeEach/afterEach/after中调用。为便于演示官方文档统一采用 mocha 的语法例如before(async () { await detox.init(); });从仓库源码看这种运行器无关的设计被贯彻到了内核detox/index.js按环境决定加载主上下文还是次上下文而所有生命周期能力都收敛在 DetoxInternalsFacade.js 中它把init、cleanup、onTestStart、onTestDone等统一暴露为detoxInternalsAPI供各测试运行器的适配器调用。一个完整测试会话的生命周期可以划分为三个阶段初始化Initial Setupdetox.init()—— 读取配置、启动服务端、加载期望/匹配器库、启动模拟器。每个用例的前后钩子Before / After Each Testdetox.beforeEach()/detox.afterEach()—— 驱动 artifacts录屏、截图、日志的启停。清理Teardowndetox.cleanup()—— 关闭服务端可选地关闭模拟器。一、初始化阶段detox.init()1.1 基本用法初始化阶段发生在detox.init()内。官方文档明确这是 Detox 读取配置、启动服务器、加载期望expectation库并启动模拟器的阶段。before(async () { await detox.init(); });当然你也可以在这个钩子里追加任何自己的初始化逻辑例如准备测试数据、设置环境变量等Detox 并不限制。1.2 源码视角init 到底做了什么从当前仓库源码看detox.init()的实质实现在 DetoxPrimaryContext.js 的[symbols.init]方法中其执行序列与文档描述一一对应解析配置调用resolveConfig(opts)底层经由configuration.composeDetoxConfig(opts)合并 CLI 参数与配置文件detox.config.js/.detoxrc/package.json中的detox字段。配置日志器根据解析出的logger配置初始化 DetoxLogger。启动 IPC 服务端创建IPCServer并init()用于协调主/次进程多 worker间的设备分配与测试结果上报。启动 WebSocket 服务端当session.autoStart为 true 时创建 DetoxServer 并open()监听ws://localhost端口等待被测 App 通过Detox.framework回连。若未显式指定端口则动态分配并写回sessionConfig.server。序列化会话状态把当前SessionState写入临时 JSON 文件并通过process.env.DETOX_CONFIG_SNAPSHOT_PATH暴露给子进程这也是detox/index.js判断主/次上下文的依据。安装 Worker若传入了workerId则安装 DetoxWorker其init中会连接服务端、校验环境、创建 artifacts 管理器、分配并启动模拟器/设备allocateDevice→bootDevice事件、安装被测 App最后把device、expect、element、by、waitFor等注入为全局变量。值得注意的是整个上下文被设计为状态机DetoxContext构造函数中将init包装为inactive → init → active、将cleanup包装为active → cleanup → inactive见 DetoxContext.js。因此主上下文只能初始化一次重复调用会抛出运行时错误Cannot initialize primary Detox context more than once.。1.3 init 的两个实用选项结合 19.x 的 DetoxObjectAPI 文档detox.init()还支持两个高频选项initGlobals: false默认情况下 Detox 会把device、expect、element、by、waitFor注入为全局变量。当你希望手动控制例如在同一进程中还需要使用 jest 原生的Expect而不被覆盖时可以关闭全局注入再显式导入const detox require(detox); before(async () { await detox.init(undefined, {initGlobals: false}); });const {device, expect, element, by, waitFor} require(detox);reuse: true默认情况下detox.init()会卸载并重新安装被测 App。若希望复用已安装的 App 以加快迭代速度可传入{reuse: true}before(async () { await detox.init(undefined, {reuse: true}); });从源码看这一行为对应 DetoxWorker.js 中behaviorConfig.init.reinstallApp的判定——该配置正是由reuse选项转换而来为 true 时跳过_reinstallAppsOnDevice重装步骤。二、每个测试的前后置钩子detox.beforeEach() / detox.afterEach()2.1 为什么强烈推荐调用它们detox.beforeEach与detox.afterEach是较新引入、目前仍属可选的生命周期函数但官方文档强烈推荐在每个用例的钩子中调用它们。原因很直接较新的特性尤其是测试 artifacts视频录制、截图、日志在没有这些调用的情况下不会被期望正常工作。其原理在源码中一目了然artifacts 的录制节奏完全由用例生命周期事件驱动。在 DetoxWorker.js 中onTestStart(testSummary)会调用artifactsManager.onTestStart(testSummary)触发日志开始、录屏开始或拍摄beforeEach.png而onTestDone(testSummary)同文件 L266-L279则调用artifactsManager.onTestDone(testSummary)完成片段收尾并拍摄afterEach.png。ArtifactsManager.js 再按升序/降序把事件分发给各插件video、screenshot、log、timeline 等。不调用这些钩子插件就永远收不到用例开始/结束信号自然无法产出按用例归类的 artifacts。TIP这一 API 未来仍可能调整。为降低升级风险官方建议优先使用内置的 mocha / jest 适配器见下文第五节而不是手写钩子。2.2 手动实现以 mocha 为例如果你使用的是 mocha 或 jest 之外的测试运行器则需要自己实现类似的逻辑并在每个用例的beforeEach/afterEach中把测试摘要test summary传给 Detoxlet testSummary; beforeEach(async function () { testSummary { title: this.currentTest.title, fullName: this.currentTest.fullTitle(), status: running, }; await detox.beforeEach(testSummary); }); afterEach(async function () { testSummary.status this.currentTest.state || failed; await detox.afterEach(testSummary); });关键点beforeEach阶段status固定为runningtitle是当前用例名fullName是含 describe 套件名的完整路径mocha 中即fullTitle()。afterEach阶段必须把status更新为passed或failed上例借用 mocha 的this.currentTest.state缺省时回退为failed再传给detox.afterEach。每个用例的title/fullName会被用于构建 artifacts 目录名详见下文TestSummary 结构。如果你的运行器足够特殊未来可以考虑把这段逻辑封装成适配器并贡献给 Detox 项目官方举例为ava.js或tape编写适配器。2.3 TestSummary 结构传给钩子的对象长什么样传给beforeEach/afterEach的testSummary对象并非随意结构19.x 的 Artifacts 文档给出了完整接口定义interface TestSummary { /** 当前测试名例如 describe(that screen) 中 it(should have a menu) 的 should have a menu */ title: string; /** 测试全名通常带套件前缀例如 that screen should have a menu */ fullName: string; /** 测试状态仅允许三个取值不接受自由字符串 */ status: running | passed | failed; /** 测试失败原因说明仅当 status failed 时可能出现 */ timedOut?: boolean; /** 测试运行器支持重试时表示这是该用例的第几次运行缺省视为 1 */ invocations?: number; }而status白名单并非文档说说而已源码有硬校验。在 DetoxWorker.js 的_validateTestSummary中testSummary必须是普通对象isPlainObject否则抛出Invalid test summary was passedstatus必须是running | passed | failed之一否则抛出Invalid test summary status。对应的单元测试见 DetoxWorker.test.js分别验证了非对象参数、非法 status、以及合法 summary 会正确触发artifactsManager.onTestStart/onTestDone。2.4 跳过pending/skipped用例的注意事项手动实现时有一条容易踩坑的规则被跳过skipped / pending的测试不应触发detox.beforeEach()也不应触发detox.afterEach()。经验法则是要么保证两者成对调用要么两者都不调用。因为只调其中一个会破坏 artifacts 插件内部的配对状态机导致后续用例的录制/截图错乱。内置适配器如 jest 的 DetoxCoreListener.js正是通过_isTestActuallyStarting判断跳过状态后才决定是否调用onTestStart你可以参考它的实现。三、清理阶段detox.cleanup()3.1 基本用法清理阶段应在所有测试执行完毕后进行通过detox.cleanup()触发。这是 Detox 服务器关闭的阶段此外如果给detox test加上--cleanup标志模拟器也会随之关闭。after(async () { await detox.cleanup(); });--cleanup标志在 CLI 文档中描述为测试结束后关闭模拟器对 CI 脚本尤其有用确保 Detox 干净退出、不残留任何进程-u, --cleanup。3.2 源码视角cleanup 的完整拆除序列主上下文的清理实现在 DetoxPrimaryContext.js 的[symbols.cleanup]中按序执行卸载 WorkeruninstallWorker()→DetoxWorker.cleanup()其中会中止未决请求、清理 artifacts 管理器、断开客户端、释放设备deallocateDevice。清理设备分配器遍历所有deviceAllocators调用cleanup()即使某个分配器清理失败也记录日志后继续保证整体流程不中断。关闭 WebSocket 服务端DetoxServer.close()见 DetoxServer.js带 10 秒优雅关闭超时超时则告警强制关闭。关闭 IPC 服务端IPCServer.dispose()。删除会话快照文件移除临时 JSON 会话文件。收尾日志结束生命周期追踪、关闭日志器并 finalize合并各进程日志。而在多进程场景下次上下文每个测试 worker 进程的清理更轻量见 DetoxSecondaryContext.js先卸载 worker再IPCClient.dispose()断开与主进程的连接。这种主进程收尾全局资源、子进程只断连接的分工正是 Detox 并行测试架构多设备、多 worker能够干净退出的关键。另外值得留意的是 DetoxPrimaryContext.js 中的_emergencyTeardown它通过signal-exit注册为进程信号退出时的兜底清理保证即使测试进程被CtrlC或信号中断模拟器分配器、WebSocket 服务端与临时文件也能被尽力回收。四、为所有测试保持一致的起点解耦测试decoupled tests是 E2E 测试的通用最佳实践每个用例从相同的起始状态出发任意顺序运行都应产生相同结果。官方强烈建议在每个用例前重启应用或重启 React Native。这一环节虽然不依赖beforeEach生命周期 API但通常与之配合使用。4.1 重启 React NativeRN 应用beforeEach(async () { await device.reloadReactNative(); });reloadReactNative只重载 JS bundle 而不重启原生进程速度快。从 Artifacts 文档 的 Timeline 插件一节可知它对应 trace 事件reloadRN便于在时间线中观察。4.2 重启整个 AppbeforeEach(async () { await device.launchApp({newInstance: true}); });launchApp({newInstance: true})会以全新实例启动 App相当于冷启动适合需要干净进程状态、或验证启动链路本身的用例。两者选择原则仅需要重置 JS 状态选reloadReactNative需要模拟冷启动、清理原生层状态如通知、剪贴板、UserDefaults选launchApp({newInstance: true})。五、内置适配器优先于手写钩子如前所述detox.beforeEach/detox.afterEach属于较薄且可能变动的手动 API。官方文档建议直接使用 Detox 内置的 mocha / jest 适配器以平滑迁移到新版本——因为 API 规范未必足够完备未来可能经历重写与扩展。以 jest 为例当前仓库的适配器链如下全局初始化/清理globalSetup.js 只做一件事——调用require(../../internals).init({ workerId: null })globalTeardown.js 则调用require(../../internals).cleanup()。它们分别对应本文第一节的detox.init()与第三节的detox.cleanup()。用例级钩子DetoxCoreListener.js 订阅 jest-circus 事件test_fn_start/hook_start时经_onBeforeActualTestStart调用detoxInternals.onTestStart(metadata)test_done时调用detoxInternals.onTestDone(metadata)见 L107-L124并自动处理跳过用例test_skip/test_todo被记录后不再触发启动钩子、超时timedOut与重试次数invocations。示例工程的落地形态可参考 examples/demo-react-native/e2e/globalSetup.ts在调用内置globalSetup前追加了 Android 场景下 TestButler APK 的下载与 examples/demo-react-native/e2e/setup.ts。mocha 侧则有 DetoxMochaAdapter.js不过当前版本已将其标记为deprecated直接 re-export 自runners/deprecation这也印证了文档中API 仍可能变化、鼓励转向内置适配器的提示。相关的 mocha 配置指引可继续阅读 19.x 的 Mocha 指南 与 Jest 指南。六、与 artifacts 的关系一张生命周期全景图把本文的钩子与 artifacts 结合一次完整运行的产出结构见 Artifacts 文档 的Artifacts Structure一节大致如下artifacts/配置名.时间戳/ ├── startup.log └── ✗ Assertions should assert an element has (accessibility) id/ ├── beforeEach.png ├── test.log ├── test.mp4 └── afterEach.png根目录按一次detox test运行创建命名含配置名与时间戳测试目录按每个用例创建其名字就是传给detox.afterEach(testSummary)的fullName上例中以✗前缀标记失败用例文件包括beforeEach.png/afterEach.png由--take-screenshots all等触发、test.log、test.mp4由--record-videos触发等。这一切的起点都是那句在beforeEach与afterEach中成对出现、且对跳过用例保持沉默的detox.beforeEach(testSummary)/detox.afterEach(testSummary)。理解了这条用例事件 → artifacts 插件的链路你就掌握了 Detox 生命周期与产物体系之间的全部耦合关系。小结初始化detox.init()一次性完成配置解析、服务端启动、全局 API 注入与设备就绪主上下文只能初始化一次。用例钩子detox.beforeEach/detox.afterEach以TestSummarytitle/fullName/status为载荷驱动 artifacts 启停status只允许running | passed | failed跳过用例务必成对地不调用。清理detox.cleanup()按序关闭 worker、设备分配器、WebSocket/IPC 服务端并清理临时文件--cleanup标志顺带关闭模拟器。一致性通过device.reloadReactNative()或device.launchApp({newInstance: true})为每个用例重置应用状态。迁移优先使用内置 jest / mocha 适配器手动钩子 API 未来可能调整。赞分享测试移动开发质量保障开发工具【免费下载链接】DetoxGray box end-to-end testing and automation framework for mobile apps项目地址https://gitcode.com/gh_mirrors/de/Detox点击查看免费下载相关推荐Powerlevel10k终极指南打造极速、美观的Zsh终端体验Powerlevel10k终极指南打造极速、美观的Zsh终端体验 你是否厌倦了单调乏味的终端界面是否觉得终端提示符加载太慢每次敲击回车都要等待几秒钟 PCLI开发工具Tape测试生命周期beforeEach、afterEach等钩子函数的终极指南Tape测试生命周期beforeEach、afterEach等钩子函数的终极指南 Tape是一个轻量级的TAP测试框架专为Node.js和浏览器环境设计。它测试开发工具5分钟掌握天勤量化TqSdk期货实时行情与量化策略开发全攻略5分钟掌握天勤量化TqSdk期货实时行情与量化策略开发全攻略 天勤量化TqSdk是专业的期货量化交易开发包让你在5分钟内就能获取实时行情数据并开始构建量化策金融科技创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

信捷XDPPro V3.8.1a安装配置全攻略:驱动签名与通信端口避坑指南
信捷XDPPro V3.8.1a安装配置全攻略:驱动签名与通信端口避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 11:42:15

Speedgoat实时控制原理与HIL测试工程实践
Speedgoat实时控制原理与HIL测试工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 11:42:15

秋招想进零售金融数据岗:银行、信用卡、消金招什么人?入职后做什么?
秋招想进零售金融数据岗:银行、信用卡、消金招什么人?入职后做什么?

零售金融,指的是银行、信用卡中心、消费金融公司、保险公司面向个人客户的业务:存款理财、信用卡、消费贷、保险。它的特点是客户多、交易频、数据量大,是金融行业里数据岗最密集、也最接近“互联网用户运营”的一块。本文分三部分&#xff1… · 2026/9/24 11:42:08

LPC18Sxx实战:MCU硬件级安全与实时控制如何兼得
LPC18Sxx实战:MCU硬件级安全与实时控制如何兼得

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:21:43

NanoTrack在RK3588上的三模型拆解与NPU适配
NanoTrack在RK3588上的三模型拆解与NPU适配

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:21:43

云原生边缘计算开源框架选型与部署实战指南
云原生边缘计算开源框架选型与部署实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:21:37

SS928评估板开发实战:从环境搭建到外设调试完整流程
SS928评估板开发实战:从环境搭建到外设调试完整流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:21:37

通快激光切割机安全开机与关机标准操作流程
通快激光切割机安全开机与关机标准操作流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/24 12:21:37

2026 YouTube 爬虫指南:视频、评论与频道数据采集实战
2026 YouTube 爬虫指南:视频、评论与频道数据采集实战

2026 最新 YouTube 数据采集实战指南!本文深度解析如何使用 Python 结合 IPFoxy 动态代理,高效突破防封限制,安全抓取 YouTube 视频元数据、评论区与频道信息。含完整代码、配置教程与常见风控避坑 QA,助你零基础搭建高可用数据爬… · 2026/9/24 12:21:24

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码