分层测试与双端验收矩阵
本页将源码检查、自动测试、界面验证、真实设备与生产验收分开。矩阵中的“期望”是测试断言或必须满足的产品边界,不表示本轮已经运行。历史记录按其日期和目标保留;所有新增执行都应记录当前基线、设备、环境、命令、结果与剩余范围。基础命令见测试,模块入口见模块地图。
环境与证据约定
每个场景至少记录 App 平台、构建、OS、网络、Account/聊天环境、合成账号代号和前置关系。正常、拒绝、断网与重启不能混为同一用例。一次失败若发生在环境准备阶段,应记为“前置条件未满足”,不能删掉或改成测试跳过后再宣称功能通过。
| 证据层 | 能确认 | 不能替代 |
|---|---|---|
| 源码与配置 | 路由、类型、校验、状态机、默认值 | 实际运行配置与业务结果 |
| 单元/本地集成 | 可重复的输入、状态和权限断言 | 真实平台回调与公网服务 |
| 系统 UI 测试 | 指定设备的元素、焦点和操作路径 | 其他屏幕、OS、硬件和商店环境 |
| 授权真机闭环 | 指定账号、设备与网络的实际结果 | 永久登录、所有地区或所有用户 |
| 正式回执 | 上传、提审、审核与发布的各自阶段 | 未记录的后续动作 |
Account 自动测试使用专用 identity_dev MySQL 与随机表前缀;聊天测试使用内存库或临时 SQLite;原生设备测试使用自己的文件和设置命名空间。禁止把生产 token、真实记忆、私人聊天或现有设备数据作为通用夹具。测试前后可核对密文数量和摘要,不读取正文证明“没有修改”。
登录与设备会话
| 场景 | 正常与拒绝 | 断网/重启及双端期望 | 验证方法 |
|---|---|---|---|
| 发起原生授权 | 随机 verifier、S256、保存 pending 后才开浏览器;错 URL 或存储失败拒绝打开 | 连点只创建当前事务;退出后的迟到响应不重新登录 | iOS ChatNativeAuthTests、Android NativeAuthTest、服务端 native-auth 测试 |
| state 与 ticket | 正确 proof 单次换票;缺失、错误、重复、取消、过期均不替换原有效账号 | 回调不能从另一环境或设备拼接;重放不产生第二个 session | 服务端验证与两端隔离状态机断言 |
| 网页到 App | 系统浏览器显示正确 Account、用户完成授权、自动回 App | 真正替换进程后回跳;需保存完整阶段与设备时间线 | 授权真机人工闭环;iOS 系统“继续”提示单独观察 |
| 会话恢复 | /me 成功恢复资料;401 清理当前凭据 |
503、超时和临时离线保留凭据;恢复网络后重试 | Android NativeAuthSessionTest;iOS 授权与 Keychain 测试,加真机恢复 |
| 退出竞态 | 本机退出并停止轮询、通话和待处理授权 | 服务端退出失败不能显示为已撤销全部会话;旧请求不能回写新账号 | 测试迟到响应、同机账号切换及离线退出 |
iOS 会保存待换票 ticket 与 API 来源,Android pending 没有相同字段,不能把 iOS 的“换票时中断可重试”结论直接套用 Android。Android 当前没有 Debug 本地 Account 信任例外,隔离普通 API 可测,隔离浏览器原生登录仍需受控测试配置。聊天会话 24 小时,无 refresh-token 路由;不得用修改系统时钟或共享真实 token 代替可控时钟测试。
联系人、消息与在线状态
| 模块与场景 | 正常期望 | 拒绝/断网/重启/双端期望 | 验证入口 |
|---|---|---|---|
| 好友申请 | 唯一好友 ID 或当前临时码发申请,对方同意后可私聊 | 自己、未知、过期码、限流与屏蔽拒绝;重开后关系仍一致 | chat.test.mjs、management.test.mjs,两合成账号与第三观察账号 |
| 群成员 | 群主邀请、改名、移除;成员按权限读取 | 非成员不可读;被移除后不可发送或拿新媒体凭证;新成员历史边界正确 | group.test.mjs、通话成员变化测试 |
| 文本去重 | 成功写入一条并产生当前用户事件 | 丢响应后使用原 clientId 重试只保留一条;换内容/换范围复用 ID 拒绝 | chat.test.mjs、MessageSendIdCoordinatorTest、iOS 聊天测试 |
| 已读与删除 | 已读位置单向前进;本人删除只改变自己的视图 | 旧读位置不倒退;恢复聊天不恢复删除前历史;双方结果分别核对 | 服务端权限断言、双端可见列表与历史分页 |
| 事件同步 | 消费普通事件 ID 并重新读取资源 | 断线保留已处理游标;重建快照不漏消息;不把消息 ID 或 MLS sequence 当普通事件游标 | chat.test.mjs 与真实网络中断后列表核对 |
| 媒体 | 上传者可读,发送引用后授权接收者可读 | 未发送、外人、删除可见历史后不能越权;重开不丢引用;大文件拒绝 | media.test.mjs、profile.test.mjs 与下载字节摘要 |
| 新事 | 好友、指定人、已登录公开、仅本人各自可见 | 解除关系、屏蔽、隐藏、删除立即影响读取;视频 Range 边界正确 | moments.test.mjs,至少三合成账号逐项比对 |
| 城市贴纸 | 内置 ID 与三端素材一致,设备城市优先 | 权限拒绝用 IP 或手选;离开会话/换账号丢弃迟到结果;坏素材不伪造成功 | city-location、city-stickers 服务端测试和原生城市测试 |
消息行应同时观察发送者和接收者,不能只凭本机气泡出现判断服务端成功,也不能凭 HTTP 200 判断对方已读。断网测试分别覆盖发送前、服务端提交后丢响应、媒体已上传但消息未发送三个时点;记录相同 clientId 的行为,避免测试本身重复点击产生另一条合法新消息。
位置、通话与系统能力
| 场景 | 期望 | 需要独立验证 |
|---|---|---|
| 实时位置 | 用户明确开始;PUT 只更新已开启共享;停止、离群或权限变化处理采集与服务端记录 | 两端前后台、粗略权限、最后更新时间、断网后旧坐标与手动停止 |
| 通话状态 | 成员才能发起/接听;重试不新建通话;响铃超时、忙、拒绝、挂断与群离开终态正确 | calls 与 call-media 测试;至少两设备逐角色检查 |
| 媒体连接 | 只有 active 当前参与者可获得短时房间 token | 麦克风、扬声器、蓝牙、摄像头切换、双向画面与声音、网络切换 |
| 系统来电 | 正确签名环境、topic、session 与设备注册 | APNs 真正到达、锁屏展示、后台、取消来电、多设备竞争接听 |
| 相机与文档 | 只读取用户选择的内容,拒绝后仍有可用替代入口 | 实体相机、无相机、永久拒绝、系统撤权、文件授权失效 |
| MLS 独立协议 | 密钥包、Welcome、Commit、ack、激活、密文重试与发件人校验 | iOS 独立传输与 Rust 测试;不能写成主聊天及全部附件 E2EE 通过 |
LiveKit 本机入房与 APNs 请求格式仅属于部分证据。媒体连接成功还应在双方分别断开与恢复、对方退群、挂断后迟到 token 等场景检查,不能让旧异步操作恢复已结束通话。普通聊天、新事、位置与推送元数据的数据可读性,应与安全边界一致。
位置退出必须单独验收:当前 iOS 退出只停止本机采集,不逐范围 DELETE 远端共享;聊天 session 注销或到期也不会自动删除 live_locations,其他仍有资格成员可能继续读取最后位置。Android 远端清理采用 bestEffort,失败时同样可能残留。用合成共享分别测试退出、到期、DELETE 成功与失败,记录本机是否采集、远端是否仍有记录、其他成员能否读取,不能把一项成功当作三项全部完成。
本机工作台、记忆与转出
| 场景 | 正常与拒绝期望 | 重启/离线/双端区别与验证 |
|---|---|---|
| 任务与收藏 | 新建、编辑、筛选、去重与最近访问按本机规则保存 | 离线可读写;同设备重开保持;另一设备不自动同步;LocalWorkspaceStoreTests、任务 UI 与 Android 工作台流程 |
| 记忆与附件 | 合法内容加密保存;空模板不落盘;字段按上限处理 | 重开、编辑、搜索与附件字节一致;iOS/Android 文件格式分别检查,不直接互拷 |
| 损坏或丢密钥 | 显示无法读取并阻止覆盖 | 不把损坏库当空库;不新建密钥覆盖旧密文;MemoryStoreTests 与 Android 医疗/转出测试 |
| 医疗与宠物 | 八项医疗字段、两段 2000 字与换行保留;宠物优先规则正确 | 英文缩写与动物词边界、未知旧字段、附件、超长内容分别回归;不用真实医疗记录 |
| 系统推荐 | iOS 系统模型可用时生成待确认结构,不可用则本机回退 | Android 固定关键词路线独立;服务器识别 API 不等于本机识别,也不等于云同步 |
| 授权转出 | 当前用户取得额外许可后才生成明文 JSON;取消不生成完整输出 | 错账号、过期、断网、文件写失败清理部分文件;当前 Account 跨服务契约未闭环,需保持待验收 |
视觉流程另检查 320 级窄屏布局、大字号、键盘、长文件名、长文本、列表空态、底栏、弹窗与保存按钮。无障碍标识只用于测试定位,仍需实际核对朗读标签、焦点与点击区域;关闭动画后页面必须可操作。预览不按展示时长自动关闭。
命令与执行记录
以下命令展示真实测试入口,本次未执行。服务端命令在 App 仓库;Account 测试应进入其当前维护仓库另行运行:
node --test chat-service/tests/native-auth.test.mjs chat-service/tests/chat.test.mjs
node --test chat-service/tests/media.test.mjs chat-service/tests/moments.test.mjs
node --test chat-service/tests/calls.test.mjs chat-service/tests/call-media.test.mjs chat-service/tests/live-location.test.mjs
zsh ios-app/scripts/test-native-auth.sh
cd android-app
./gradlew :app:testDebugUnitTest --max-workers=1 \
-Dorg.gradle.jvmargs=-Xmx1g -Pkotlin.compiler.execution.strategy=in-process
cd identity
npm run typecheck
npm test
npm --prefix client test
设备用例必须先指定允许使用的 QA 目标,串行执行,不卸载现有 App,不 wipe 模拟器或清 Keychain。历史医疗 QA 记录了 iOS 37 项本机测试、Android 69 项单测及专项 UI;原生授权记录包含 iOS 16 项测试与 Android 85 项 JVM、5 项隔离设备测试。Android 另有一次真实授权与 force-stop 冷启动记录;iOS 完整真实账号回跳、审核 iPad、生产推送、跨网音视频、正式包和手表独立版仍需新的证据。
每条验收结果填写:场景 ID、当前基线、期望、实得、退出码、日志摘要、目标设备、是否改变夹具、复验结果与未覆盖项。失败记录保留并关联修复后的结果;统计数量只能帮助追溯,不能替代具体断言或成为生产功能保证。发行门禁见发行清单。