测试执行与状态机
基本信息
| 属性 | 值 |
|---|---|
| 状态枚举 | com.gtnewhorizons.horizonqa.internal.GameTestStatus |
| 状态值数 | 7 |
| 阶段枚举 | com.gtnewhorizons.horizonqa.internal.TestPhase(START / END) |
| 执行器 | internal/GameTestRunner.java |
| 单例 | internal/InteractiveTestSession.java |
| 网格布局 | internal/GameTestGridLayout.java |
| 区块加载 | internal/GameTestChunkLoader.java(实现 ForgeChunkManager.OrderedLoadingCallback) |
| 启动钩子 | CommonProxy.serverStarting(CommonProxy.java:92) |
| 关服钩子 | CommonProxy.serverStopping(CommonProxy.java:145) |
功能
状态机
GameTestStatus 定义 7 个状态(GameTestStatus.java:3-11):
| 状态 | 含义 |
|---|---|
NOT_STARTED |
初始态,尚未开始 |
RUNNING |
执行中 |
SKIPPED |
跳过(如所需 mod 未加载) |
PASSED |
通过 |
FAILED |
断言失败 |
ERROR |
运行期异常 |
TIMED_OUT |
超时 |
isDone() 对除 NOT_STARTED 与 RUNNING 外的 5 个终态返回 true(GameTestStatus.java:13-15)。
GameTestInstance 用它防止重复启动:if (status != GameTestStatus.NOT_STARTED) return;
(GameTestInstance.java:104)。
START / END 两阶段
每个测试有 START 与 END 两个阶段(TestPhase.java:3-6)。
GameTestInstance 在对应 tick 边界分别驱动序列:
- START 阶段:
sequence.tick(tickCount, TestPhase.START)(GameTestInstance.java:139) - END 阶段:
sequence.tick(tickCount, TestPhase.END)(GameTestInstance.java:181)
序列(GameTestSequence)把断言排成有序步骤,每步都在指定 tick 执行;
步骤超时抛 SequenceStepTimeoutException,它保留步骤快照与最后一次断言的带位置 cause
(SequenceStepTimeoutException.java:11-18)。
网格布局
测试格按网格排列,互不重叠。GameTestGridLayout 的常量(GameTestGridLayout.java:7-10):
| 常量 | 值 | 含义 |
|---|---|---|
DEFAULT_CELL_SIZE |
5 | 最小格尺寸(X / Z) |
INTER_CELL_GAP |
3 | 相邻格之间的空隙 |
MAX_PER_ROW |
10 | 每行最多 10 个测试格 |
分配逻辑(GameTestGridLayout.allocateOrigin,GameTestGridLayout.java:30-49):
格宽 = max(模板尺寸X, 5) + 3,格深同理;一行满 10 个后换行,行深取该行最深格 + 间隙。
原点来自 -Dhorizonqa.gridOrigin(默认 0,64,0)。
每个格记录为 TestCell record,字段为
testId, originX, originY, originZ, minX, minY, minZ, maxX, maxY, maxZ(TestCell.java:5-6)。
区块强制加载
GameTestChunkLoader 实现 ForgeChunkManager.OrderedLoadingCallback,
在 preInit 通过 ForgeChunkManager.setForcedChunkLoadingCallback 注册
(CommonProxy.java:75)。它把测试格的包围盒换算成区块坐标并申请 Ticket
(GameTestChunkLoader.java:25-40),确保 fixture 所在区块不被卸载。
forceChunks— 遇到TemplateException只记警告(GameTestChunkLoader.java:24-31)forceChunksStrict— 抛异常,供严格路径使用(GameTestChunkLoader.java:33-40)- 关服时释放:
ReportedRun.shutdown()失败则兜底CHUNK_LOADER.releaseAll()(CommonProxy.java:146-149)
生命周期
服务端启动(CommonProxy.java:92-143):
ReportedRun.clearLastResult()- 若 mode 解析出错 → 以配置失败上报并返回
- 若
mode == off→ 直接返回(不发现测试、不注册指令) InteractiveTestSession.reset()GameTestRegistry.discoverTests(asmData)发现测试event.registerServerCommand(new HorizonQACommand(catalog))注册指令- 若非自动运行 → 返回(等待玩家用指令触发)
- 按属性选择测试,收集基础设施问题
new ReportedRun(...).start()启动
服务端停止(CommonProxy.java:145-151):释放区块、重置会话、关闭 runner、清空上次结果。
数值
| 数值名 | 值 | 来源 |
|---|---|---|
| 状态数 | 7 | GameTestStatus.java:3-11 |
终态数(isDone()) |
5 | GameTestStatus.java:13-15 |
| 阶段数 | 2(START / END) |
TestPhase.java:3-6 |
| 网格最小格尺寸 | 5 | GameTestGridLayout.java:7 |
| 网格格间隙 | 3 | GameTestGridLayout.java:8 |
| 每行最大格数 | 10 | GameTestGridLayout.java:9 |
| 网格默认原点 | 0, 64, 0 |
HorizonQAProperties.java:30 |
| 默认超时 tick | 100 | api/annotation/GameTest.java:17 |
| turbo 倍率上限 | 100 | HorizonQAProperties.java:29 |
turbo 加速
MixinMinecraftServer 用 @Redirect 拦截 MinecraftServer.run 中的 MinecraftServer.tick() 调用
(mixin/MixinMinecraftServer.java:26-31),在 turbo 生效时循环调用 server.tick() 指定次数。
倍率来自 -Dhorizonqa.turbo(1–100,默认 1)。
虚空世界
ci 模式下默认使用虚空世界策略(HorizonQAProperties.java:426)。
GameTestWorldType 的世界类型名为 gtnhvoid(GameTestWorldType.java:10),
自定义 getSpawnFuzz() 返回 1、getMinimumSpawnHeight() 返回 64
(GameTestWorldType.java:28-35),区块管理器与生成器分别由
VoidWorldChunkManager / VoidChunkProvider 提供。
交互
隔离与并发
- 同一时刻只允许一个批次执行,由
GameTestRunner.isBatchActive()判定;/horizonqa的多数子指令在执行中会拒绝新请求 - 测试隔离违规抛
TestIsolationViolation(api/TestIsolationViolation.java) - 基础设施异常抛
GameTestInfrastructureException(api/GameTestInfrastructureException.java)
异常类型
| 异常 | 继承 | 用途 |
|---|---|---|
GameTestAssertException |
— | 断言失败基类 |
SequenceStepTimeoutException |
GameTestAssertException |
序列步骤超时(SequenceStepTimeoutException.java:7) |
GameTestAssumptionException |
— | assumeTrue / assumeFalse 失败 |
GameTestInfrastructureException |
— | 基础设施错误 |
LabelResolutionException |
— | 结构标签无法解析 |
TestIsolationViolation |
— | 隔离违规 |
TemplateException |
— | 结构模板问题(structure/TemplateException.java) |
GTVersionMismatchException |
— | GT 版本不匹配 |
标记常量
CaseResult 定义了 4 个字符串标记(CaseResult.java:24-27):
| 标记 | 含义 |
|---|---|
TEMPLATE_ERROR |
结构模板加载 / 放置失败 |
CLEANUP_ERROR |
清理阶段出错 |
ASSUMPTION_FAILED |
前提条件不成立 |
MISSING_REQUIRED_MOD |
@GameTestHolder.requiredMods 中有 mod 缺失 |
相关条目
- 报告输出 - 终态如何写进 JUnit XML 与状态 JSON
- 测试注解与发现 -
@GameTest定义的测试如何进入队列 - GameTestHelper API - 测试体内可调用的方法
- JVM 系统属性 -
turbo/gridOrigin/world等开关