15 KiB
15 KiB
帧动画系统第一、二阶段手动测试方案
1. 测试目标
本文档用于手动验收帧动画系统前两个阶段:
- 第一阶段:数据模型、Graph 解析、运行时播放器、统一求值器和播放 Handle。
- 第二阶段:Aseprite JSON 解析、ImportSource、差异预览、稳定刷新、只读 Sprite 匹配和自动切图。
测试重点是验证实际工作流和资产稳定性,不验收第三阶段的完整 Graph 工作台、节点画布或正式删除流程。
2. 测试前准备
2.1 环境
- Unity:2022.3.7f1c1。
- 打开项目后等待脚本编译完成。
- 清空 Console,确认没有编译错误。
- 打开
Window > General > Test Runner,确认可以看到:AibisDream.FrameAnimation.Tests.EditModeAibisDream.FrameAnimation.Tests.PlayMode
2.2 生成测试样例
依次执行:
Tools > Frame Animation > Rebuild Runtime SampleTools > Frame Animation > Rebuild Import Sample
生成内容:
- 运行时样例场景:
Assets/Scenes/FrameAnimationRuntimeTest.unity - 第一阶段样例:
Assets/GameContent/Test/FrameAnimation/ - 第二阶段样例:
Assets/GameContent/Test/FrameAnimation/Import/
第二阶段测试中可以修改 Import 文件夹内的测试 JSON。测试结束后再次执行 Rebuild Import Sample 即可恢复,不要修改生产动画资源。
2.3 测试记录
每个用例记录:
| 项目 | 内容 |
|---|---|
| 结果 | 通过 / 失败 / 阻塞 |
| 实际表现 | 简述观察结果 |
| Console | 是否出现 Error/Exception |
| 证据 | 截图、录屏或相关资产路径 |
| 缺陷 | 可复现步骤和预期/实际差异 |
3. 第一阶段:运行时播放测试
RT-01 样例场景基础播放(P0)
操作:
- 打开
FrameAnimationRuntimeTest.unity。 - 进入 Play Mode。
- 同时观察左侧 SpriteRenderer 和右侧 UI Image。
- 选中两个对象,在
FrameAnimationPlayerInspector 中观察 Runtime State。
预期:
- 左侧
Flow Sample - SpriteRenderer立即显示 Intro 第 0 帧。 - 左侧约 1.25 秒后从 Intro 自动进入 Idle,之后持续循环 Idle。
- 左侧 Playable 始终为
IntroToIdle,Clip 从Intro变为Idle。 - 右侧
Direct Idle - Image立即显示 Idle 第 0 帧并持续循环。 - 右侧 Playable 和 Clip 均为
Idle,Node 为空。 - 两个目标均不依赖 Animator 或 AnimatorController。
- Console 没有 Error 或 Exception。
RT-02 长时间循环稳定性(P0)
操作:
- 保持样例场景运行至少 60 秒。
- 观察两个目标和 Inspector 中的帧索引。
预期:
- Idle 每约 4 秒循环一次。
- 不出现停播、闪空、越界帧或明显累计漂移。
- 内存和 Console 不持续产生异常或日志刷屏。
RT-03 动态速度(P0)
操作:
- Play Mode 中将 Player 的 Speed 改为
0。 - 等待数秒,再改为
0.5、2,最后恢复1。
预期:
- Speed 为
0时停在当前帧,但 State 仍为 Playing。 - 恢复正数后从当前进度继续,不从头重播。
0.5明显变慢,2明显变快。- 不丢失 Flow 节点或当前 playable。
RT-04 Pause/Resume、Stop 和 Handle 语义(P0)
操作:
- 在 Test Runner 中运行第一阶段 EditMode 测试。
- 重点查看 PlaybackSession、PlaybackHandle、Stop、Pause/Resume 和替换请求相关用例。
预期:
- Pause 不改变当前帧,Resume 从原进度继续。
- 新的合法 Play 将旧请求以 Replaced 结算。
- Stop 将活动请求以 Stopped 结算。
- 正常播完以 Completed 结算。
- 无效请求以 Failed 结算,且不会打断正在播放的合法请求。
- Task、协程和回调观察到同一个结果,每个请求只结算一次。
说明:当前样例 Inspector 只展示状态,没有完整运行时控制面板,因此这一组 API 语义以 Test Runner 的可重复结果作为验收依据。
RT-05 Disable/Enable 生命周期(P0)
操作:
- Play Mode 中等待动画进入非首帧。
- 禁用
FrameAnimationPlayer组件。 - 观察显示目标和 Runtime State。
- 重新启用 Player。
- 再对整个 GameObject 执行一次禁用和启用。
预期:
- 禁用时活动请求以 Stopped 结束。
- 当前 Sprite 保留,不自动 Clear 或 Hide。
- 重新启用时,因为
playOnEnable = true,默认 playable 从头播放。 - 左侧重新从 Intro 第 0 帧开始,右侧重新从 Idle 第 0 帧开始。
RT-06 目标配置校验(P0)
在临时场景或复制对象上执行,测试后不要保存改动。
| 配置 | 预期 |
|---|---|
| Player,无 SpriteRenderer/Image | Inspector 显示缺失目标错误,Play 返回 Failed |
| Player + SpriteRenderer + Image | Inspector 显示目标冲突,Play 返回 Failed |
| Player + 唯一目标,但 Graph 为空 | Inspector 显示 Graph 缺失,Play 返回 Failed |
| Speed 为负数 | Inspector 显示非法速度;运行时 SetSpeed 不接受负值 |
失败请求不得清空或替换其他对象上正在播放的合法动画。
RT-07 Clear 与 HideTarget(P1)
操作:
- 在 PlayMode Test Runner 中运行 Clear/HideTarget 相关用例。
- 检查 SpriteRenderer 和 Image 两套目标的结果。
预期:
- Clear:Sprite 变为 null,但显示组件仍启用。
- HideTarget:只禁用 SpriteRenderer 或 Image。
- Hide 后再次成功 Play 会重新启用目标,并立即显示第 0 帧。
- SpriteRenderer 与 Image 语义一致。
4. 第二阶段:Aseprite 导入测试
IMP-01 样例与中文数据(P0)
操作:
- 执行
Rebuild Import Sample。 - 选中
ImportSampleGraph.asset。 - 展开 Import Sources。
- 点击
Preview All Enabled。
预期:
- 存在 Object/只读切图和 Array/自动切图两个来源。
- internalId 是只读 GUID,并可复制。
- 中文来源名、Tag 和 frameName 没有乱码。
- 可看到
待机、眨眼、转身、惊讶等 Imported Clip。 - 初始预览不出现 Error;成功构建后 Clip 状态应为 Unchanged。
- Imported Clip 显示为 Graph 的 sub-asset,而不是独立
.asset。
IMP-02 Object/Array 与 direction(P0)
操作:
- 在 Test Runner 中运行第二阶段 Parser 和 TagExpansion 测试。
- 查看 Object、Array 和四种 direction 用例。
预期:
- Object 和 Array 得到相同语义的 SourceFrame。
- Object 帧顺序保持 JSON 属性原始顺序,不按名称重新排序。
forward、reverse、pingpong、pingpong_reverse顺序正确。- pingpong 不重复首尾端点,单帧 Tag 只产生一帧。
IMP-03 普通内容更新与原地刷新(P0)
操作:
- 在 Project 窗口展开
ImportSampleGraph,选中任意 Imported Clip并保持 Inspector 锁定。 - 打开对应测试 JSON,将该 Tag 使用帧的
duration改为另一个正整数。 - 回到 Unity,等待 JSON 重新导入。
- 点击对应来源的
Preview Source。 - 确认显示 SourceChanged Warning 和 Updated Clip。
- 点击
Refresh Source。
预期:
- Preview 不直接修改 Clip。
- Refresh 后仍是原来的 Clip sub-asset,锁定的引用不丢失。
- Clip 的帧时长更新。
displayName、speed和defaultEndBehavior不被覆盖。- 刷新后再次 Preview,状态变为 Unchanged,来源变化 Warning 消失。
IMP-04 用户重命名 Clip id 后刷新(P0)
操作:
- 选择一个未作为默认 playable 的 Imported Clip。
- 将 Clip
id、displayName和speed改为自定义值。 - 修改其源 JSON 的 duration。
- 对来源执行 Preview 和 Refresh。
预期:
- 刷新仍通过
importSourceId + sourceTagName找到原 Clip。 - frames 被更新。
- 用户设置的 id、displayName、speed 和结束行为保持不变。
- 不会因为 Clip id 已改变而创建重复 Clip。
测试完成后执行 Rebuild Import Sample 恢复样例,避免重命名影响默认 playable 或 Flow 引用。
IMP-05 Tag Missing 与恢复(P0)
操作:
- 从 Object 测试 JSON 的
frameTags中暂时删除待机条目,不删除 frames。 - 点击
Preview Source。 - 确认
待机显示 Missing,再执行 Refresh。 - 检查 Graph sub-assets。
- 将原 Tag 完整恢复,再次 Preview 和 Refresh。
预期:
- Tag 消失时原 Clip 保留,只设置
isMissingFromSource = true。 - 原 Clip 的 Sprite 和帧表不被自动删除。
- Missing Clip 在完整 Graph 校验中报告错误。
- Tag 恢复后更新同一个 Clip,并清除 Missing。
- Node、Flow 或其他对象对原 Clip 的引用不丢失。
IMP-06 Tag 改名规则(P1)
操作:
- 将测试 JSON 中一个 Tag 改为全新的、不冲突的名称。
- Preview 并 Refresh。
预期:
- 旧 Tag 对应 Clip 变为 Missing。
- 新 Tag 创建新的 Imported Clip sub-asset。
- 系统不猜测两者关联,也不迁移旧引用。
执行 Rebuild Import Sample 恢复样例。
IMP-07 只读 Sprite 匹配(P0)
操作:
- 选择 Object/只读切图来源,确认
manageSpriteSlicing = false。 - 记录对应 PNG
.meta的 Git diff 状态。 - Preview 和 Refresh 一次未变化的来源。
- 将 JSON 中一个 frame rect 改成无法匹配已有 Sprite 的位置,再 Preview。
预期:
- 正常情况下按 frameName 和 rect 唯一匹配现有 Sprite。
- 未变化刷新不会修改 TextureImporter 或 PNG
.meta。 - rect 无法匹配时出现 SpriteMatchFailed Error。
- 系统不会自动改切图,也不会应用 Graph/Clip 修改。
IMP-08 自动切图与稳定 Sprite ID(P0)
操作:
- 选择 Array/自动切图来源,确认
manageSpriteSlicing = true。 - 将某个 Sprite 拖到临时场景中的 SpriteRenderer,形成真实序列化引用。
- 修改 JSON 中该 frame 的 rect,但保持 frameName 不变且 rect 合法。
- 点击
Preview Source。 - 检查 Sprite diff 后点击
Refresh Source,确认 TextureImporter 修改对话框。
预期:
- 差异明确显示 Updated SpriteRect。
- 必须确认后才修改 TextureImporter。
- 刷新后同名 Sprite 保持原 spriteID。
- 临时 SpriteRenderer 的 Sprite 引用不变,不出现 Missing。
- rect/pivot 更新为 JSON 和 ImportSource 设置。
- JSON 中消失的 frameName 对应旧 SpriteRect仍保留。
IMP-08A 合并帧共享 Sprite(P0)
操作:
- 使用包含多个 SourceFrame 指向相同
frame.x/y/w/h的 Aseprite JSON。 - 确认来源设置为
manageSpriteSlicing = true,点击Preview Source。 - 检查来源摘要中的逻辑帧、SpriteSlot 和共享别名数量。
- 确认刷新后检查对应 Imported Clip 的帧表和 Sprite引用。
- 再次执行 Preview 和 Refresh。
佩佩素材的预期统计:
- 347 个逻辑 SourceFrame。
- 205 个唯一 SpriteSlot。
- 142 个共享别名。
预期:
- 相同 rect 只创建一个有效 SpriteRect。
- 不同 SourceFrame仍保留各自的 frameName、sourceIndex、duration 和 Tag顺序。
- 指向同一 rect 的 Clip Frame直接引用同一个 Unity Sprite。
- 第二次 Preview 中 SpriteSlot 和 Clip均显示 Unchanged,Sprite ID保持稳定。
- 原始 PNG 和 JSON不被修改。
IMP-09 多写入所有者冲突(P0)
操作:
- 在样例 Graph 中点击
Add ImportSource。 - 启用新来源,绑定自动切图来源正在使用的同一 Texture 和任意有效 JSON。
- 设置
manageSpriteSlicing = true。 - 点击
Preview All Enabled。
预期:
- 出现 TextureOwnershipConflict Error,并列出冲突来源。
- Refresh 不修改 TextureImporter、Graph 或 Clip。
- 将新增来源禁用后冲突消失。
测试完成后执行 Rebuild Import Sample 清理额外来源。
IMP-10 阻断错误与单来源原子性(P0)
依次测试以下任一错误:
- duration 改为
0。 - frame rect 越出 Texture。
trimmed = true。rotated = true。- direction 改为未知值。
- Tag 范围越界。
操作:
- 先记录当前 Clip 帧表和 Texture
.meta。 - 制造错误并点击
Preview Source。 - 再点击
Refresh Source。
预期:
- Preview 显示具体结构化 Error。
- 不出现部分 Clip 更新。
- TextureImporter 和
.meta不变化。 lastSourceHash不更新。- 现有 Clip 和 sub-asset 引用保持原样。
IMP-11 全部来源原子性(P0)
操作:
- 在一个来源中修改合法 duration,使其产生 Updated。
- 在另一个来源中制造 duration 为
0的阻断错误。 - 点击
Preview All Enabled,然后点击Refresh All Enabled。
预期:
- 预览同时显示合法变化和阻断错误。
- 因任一启用来源失败,整批刷新不应用。
- 合法来源的 Clip 也保持刷新前状态。
- 两个来源的 hash 均不更新。
IMP-12 命名冲突(P1)
分别制造:
- 两个启用 ImportSource 使用同名 Tag。
- 新 Tag 与现有 Clip id 同名。
- 新 Tag 与现有 Flow id 同名。
预期:
- Preview 显示 TagConflict 或 PlayableIdConflict。
- 错误信息能够指出来源和冲突名称。
- 系统不自动加前缀、不自动改名、不创建部分 Clip。
IMP-13 Undo/Redo 与保存稳定性(P1)
操作:
- 执行一次成功的 duration 刷新。
- 使用 Undo,检查 Clip 帧表和来源 hash。
- 使用 Redo,再次检查。
- 保存项目,关闭并重新打开 Unity。
- 重新检查 Graph、Imported Clip、ImportInfo 和中文名称。
预期:
- Undo/Redo 对 Graph 和 Clip 修改成组生效。
- 新建 sub-asset 不留下孤立对象。
- 重启后中文名称、sourceTagName、internalId 和引用不变化。
- 再次 Preview 能正确判断当前来源是否已刷新。
5. 自动测试回归
手动测试完成前至少执行:
- Test Runner > EditMode > Run All。
- Test Runner > PlayMode > Run All。
通过标准:
- 第一阶段既有测试全部通过。
- 第二阶段 Parser、direction、只读匹配、稳定 sub-asset、Missing 和所有权测试全部通过。
- 没有新增 Console Error 或未处理 Exception。
6. 总体验收标准
以下项目全部满足后,第一、二阶段可视为通过:
- 不依赖 AnimatorController 即可播放直接 Clip 和线性 Flow。
- SpriteRenderer 与 Image 的首帧、循环、速度、生命周期和显示语义正确。
- 播放请求完成原因和 Failed 隔离符合定义。
- Object/Array Aseprite JSON 均能正确解析,中文数据稳定。
- Imported Clip 能新增、原地更新、Missing 和恢复。
- 用户拥有字段不会被刷新覆盖。
- 只读来源绝不修改 TextureImporter。
- 自动切图为同名 frameName 保留稳定 Sprite ID。
- 合并帧只创建唯一 SpriteSlot,同时保留全部逻辑帧时长与播放顺序。
- 多写入所有者、素材错误和命名冲突能够阻断刷新。
- 单来源和全部来源刷新都不产生部分 Graph/Clip 更新。
- 保存、Undo/Redo 和重新打开 Unity 后资产引用保持稳定。
若任一 P0 用例失败,先停止进入第三阶段并记录缺陷;P1 问题可以评估后决定是否阻断,但不得破坏资产引用、原子刷新或运行时播放语义。