Minecraft Fabric服务端模组单元测试搭建方案
Fabric服务端模组测试落地方案
基础规则:先解决测试代码混入生产包的问题
别用配置布尔开关的方案,直接用Gradle标准目录结构隔离代码:
- 生产代码放
src/main/java,只有这部分代码会被打进最终发布的mod jar - 不依赖游戏运行的单元测试代码放
src/test/java,Gradle执行test任务时才会编译加载,完全不会进入生产包 - 需要依赖Fabric/Minecraft类的集成测试代码放
src/testmod/java,Fabric Loom插件会把这部分打成独立的测试附属mod,只有跑测试任务时才会加载,和生产代码完全隔离
对应三个测试要求的实现方式
1. 验证代码可正常编译
直接用Gradle原生的build任务即可,现有CI里的构建步骤已经覆盖这部分:只要./gradlew build执行过程中没有报错,就说明代码编译、依赖声明都没有问题,不需要额外加逻辑。
2. 验证代码可在Fabric服务端正常运行
优化现有CI里的服务端启动步骤,不用写额外代码:
- 用Fabric Loom自带的
runServer任务启动服务端,不要自己手动拼服务端包 - CI脚本里监听服务端日志,当出现
Done! For help, type "help"字样时,说明服务端、所有mod已经完全加载完成,没有启动崩溃 - 检测到加载完成后等待10秒,向服务端进程输入
stop指令正常关服,整个过程没有报错、崩溃就算通过 - 如果启动过程中出现mod加载失败、类缺失、初始化异常,任务会直接退出,CI会判定为失败
3. 全功能逻辑覆盖(SQL读写、事件触发)
这部分分两层做,兼顾测试速度和覆盖度:
第一层:纯单元测试(不启动游戏,速度快)
先把核心逻辑和Fabric事件、Minecraft类解耦:
- 不要把SQL读写逻辑直接写在玩家加入/离开的事件监听器匿名类里,单独抽一个
PlayerDataSyncService类,把loadPlayerData、savePlayerData两个核心方法做成独立公开方法 - 把需要同步的玩家字段(UUID、用户名、背包、经验、位置等)抽成普通Java POJO,核心同步逻辑只和这个POJO、数据源打交道,不直接依赖
ServerPlayer这类Minecraft类 - 事件监听器只做参数转换:玩家加入事件触发时,从
ServerPlayer实例里提取字段,调用syncService的load方法拿到POJO,再把POJO里的值写回玩家对象;玩家离开时同理,从玩家对象提取字段生成POJO,调用save方法写库 - 单元测试里直接用Junit5跑核心逻辑,数据库用H2的MySQL兼容模式做内存库,不需要搭真实MySQL服务,直接测SQL建表、读写、更新、异常处理的逻辑对不对,这部分在
./gradlew test任务里自动执行。
第二层:集成测试(启动Fabric服务端,覆盖事件逻辑)
用Fabric官方提供的GameTest框架做,不需要自己搭模拟玩家连接的逻辑:
- 测试代码全部放在之前说的
src/testmod/java目录,注册一个测试专用的mod入口点,只有跑测试任务时才会加载 - 监听
ServerLifecycleEvents.SERVER_STARTED事件,在服务端完全启动后自动执行测试用例:- 先把模组的数据源切换到测试用的H2内存库,清空测试数据
- 用
GameTestHelper.createMockServerPlayer()方法创建服务端侧的模拟玩家对象,不需要真实客户端连接 - 手动触发玩家加入流程:可以直接调用你自己写的加入事件处理逻辑,也可以通过Fabric事件总线抛出玩家加入对应事件,之后校验:模拟玩家的对应字段有没有被正确赋值、测试库里有没有生成对应玩家的初始记录
- 修改模拟玩家的测试字段(比如修改经验值、给背包加测试物品),再触发玩家离开事件,之后校验测试库里的对应记录有没有同步更新
- 所有断言通过就标记测试成功,任意步骤失败直接抛出异常,让服务端异常退出,CI就能捕获到失败
- 这部分配置到
runGametest任务里,CI执行./gradlew runGametest就能自动跑完所有用例,跑完会自动退出,不需要人工干预。
CI工作流最终执行顺序
现有GitHub Actions只要按顺序跑三个命令就能覆盖所有测试要求:
./gradlew test:执行所有单元测试,同时完成代码编译校验./gradlew runServer:完成mod服务端加载校验./gradlew runGametest:执行全链路集成测试,覆盖事件触发、SQL读写逻辑
不要用配置开关的方案:这种方式会把测试逻辑打进生产jar,不仅会增加jar体积,一旦开关逻辑写漏,还有可能在生产环境触发测试逻辑,污染线上数据库,用Gradle标准目录隔离是Java生态通用的成熟方案,没有这类风险。
内容的提问来源于stack exchange,提问作者Hampus Toft
相关产品推荐
相关产品推荐

