测试执行与状态机

基本信息

属性 值
状态枚举 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):

  1. ReportedRun.clearLastResult()
  2. 若 mode 解析出错 → 以配置失败上报并返回
  3. 若 mode == off → 直接返回(不发现测试、不注册指令)
  4. InteractiveTestSession.reset()
  5. GameTestRegistry.discoverTests(asmData) 发现测试
  6. event.registerServerCommand(new HorizonQACommand(catalog)) 注册指令
  7. 若非自动运行 → 返回(等待玩家用指令触发)
  8. 按属性选择测试,收集基础设施问题
  9. 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 缺失

相关条目