mcpField
R
roblox-testing

roblox-testing

github.com/el4cteo测试与质量54511 次安装2 周前更新
代码仓库

关于 roblox-testing

面向 Roblox 游戏开发者的测试指南,介绍如何组织可测试代码、使用 Jest Lua 编写测试,以及在 Studio、CLI 和云端执行测试。还包含多人游戏测试方法与发布前检查清单。

主要功能

  1. 01将游戏逻辑拆分为纯模块
  2. 02通过依赖注入使用测试替身
  3. 03使用 Jest Lua 编写和运行测试
  4. 04在 Studio、CLI 或云端执行测试
  5. 05用多客户端和设备模拟器进行试玩
  6. 06按发布前清单检查功能

适用场景

  1. 01验证库存、伤害或商店逻辑
  2. 02用内存替身测试数据服务
  3. 03在 CI 中运行无头测试
  4. 04检查多人同步与跨设备体验

MCP 相关

介绍 Studio MCP 的 `execute_luau`、`start_stop_play` 和 `get_console_output`,供 Agent 对打开的场景运行测试与试玩。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/el4cteo/roblox-skills --skill roblox-testing

安装后在 Claude Code 中输入/roblox-testing确认已加载。

附带文件references/cloud-test-runner.md

详细介绍

测试 Roblox 游戏

先让代码具备可测试性

  • 将游戏规则放在纯 ModuleScripts 中(输入 → 输出,不使用服务、不让出执行权):伤害公式、 背包操作、商店定价、状态机、序列化、校验。这些都能轻松测试。
  • 服务通过参数接收依赖(依赖注入),这样测试就可以传入伪对象, 而不必使用真实的 DataStore、远程事件或 Players。
--!strict
-- ReplicatedStorage/Shared/Inventory.luau — pure logic, no Roblox services.
export type Inventory = { [string]: number }

local Inventory = {}

function Inventory.add(inventory: Inventory, itemId: string, amount: number, maxStack: number): (boolean, string?)
	if amount <= 0 or amount ~= math.floor(amount) then
		return false, "invalid amount"
	end
	local current = inventory[itemId] or 0
	if current + amount > maxStack then
		return false, "stack full"
	end
	inventory[itemId] = current + amount
	return true, nil
end

return Inventory
--!strict
-- A service that receives its data store, so tests can inject an in-memory fake.
type Store = {
	GetAsync: (self: Store, key: string) -> any,
	SetAsync: (self: Store, key: string, value: any) -> (),
}

local function newCurrencyService(store: Store)
	local service = {}
	function service.award(userId: number, amount: number): number
		local key = `User_{userId}`
		local balance = (store:GetAsync(key) or 0) + amount
		store:SetAsync(key, balance)
		return balance
	end
	return service
end

-- In tests: a fake store backed by a table.
local fakeData: { [string]: any } = {}
local fakeStore: Store = {
	GetAsync = function(_self, key)
		return fakeData[key]
	end,
	SetAsync = function(_self, key, value)
		fakeData[key] = value
	end,
}
print(newCurrencyService(fakeStore).award(1, 50))

return newCurrencyService

Jest Lua(推荐框架)

Jest 的移植版(describe/it/expect、模拟、快照)。TestEZ 已过时;Jest Lua 3 包含迁移指南。

# wally.toml
[dev-dependencies]
Jest = "jsdotlua/[email protected]"
JestGlobals = "jsdotlua/[email protected]"
-- src/shared/Inventory.spec.luau
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local JestGlobals = require(ReplicatedStorage.DevPackages.JestGlobals)
local Inventory = require(ReplicatedStorage.Shared.Inventory)

local describe, it, expect = JestGlobals.describe, JestGlobals.it, JestGlobals.expect

describe("Inventory.add", function()
	it("stacks items up to the limit", function()
		local inventory = {}
		expect(Inventory.add(inventory, "Apple", 3, 5)).toBe(true)
		expect(inventory.Apple).toBe(3)
		local ok, reason = Inventory.add(inventory, "Apple", 3, 5)
		expect(ok).toBe(false)
		expect(reason).toBe("stack full")
	end)

	it("rejects fractional amounts", function()
		expect(Inventory.add({}, "Apple", 0.5, 5)).toBe(false)
	end)
end)
  • 在每个测试根目录中放置一个 jest.config.luau(return { testMatch = { "**/*.spec" } })。
  • Runner 脚本(Studio 命令栏、测试 place 的 Script,或云任务): require(ReplicatedStorage.DevPackages.Jest).runCLI(root, { ci = true }, { root }):awaitStatus() → 检查 result.results.numFailedTests。
  • 本地运行 Jest Lua 3 时,Studio 的 ClientAppSettings.json 中需要启用快速标志 FFlagEnableLoadModule = true。
  • 仅在测试构建中将 DevPackages 映射到 DataModel(使用单独的 Rojo 项目,例如 test.project.json)。

测试运行位置

Runner用途
Studio(命令栏 / 测试 Script)本地开发。
Studio MCP(execute_luau、start_stop_play、get_console_output)Agent 在打开的 place 中运行测试和游玩测试——参见 roblox-studio-mcp。
run-in-roblox会打开 Studio、运行脚本并传递输出的 CLI(需要安装 Studio;适用于本地 / Windows / mac CI Runner)。
Open Cloud Luau Execution无头 CI:在已发布 place 版本对应的真实 Roblox 服务端中运行脚本。
Lune不依赖 Roblox API 的纯 Luau 模块(速度快,可在任何环境运行)。

Open Cloud Luau Execution 流程(详情和脚本见:references/cloud-test-runner.md):

  1. 构建测试 place(rojo build test.project.json -o test.rbxl),并将其上传为专用测试 place 的已保存版本。
  2. 使用 { "script": ... } 调用 POST /cloud/v2/universes/{u}/places/{p}/versions/{v}/luau-execution-session-tasks (API 密钥范围 universe.place.luau-execution-session:write;每位密钥所有者的速率限制约为每分钟 5 个任务)。
  3. 轮询任务 path,直到 state 变为 COMPLETE / FAILED;读取 output.results 和 .../logs。

在 Studio 中进行游玩测试

  • Test 选项卡:Play(你和服务端)、Run(仅服务端,无角色)、Clients and Servers(使用 2 个或更多玩家测试复制、交易和 PvP)。大多数多人游戏 Bug 只有在客户端数量 ≥ 2 时才会出现。
  • Device Simulator 工具栏(Test → Device Simulator,视口顶部):在游玩测试期间切换手机 / 平板 / 主机,并显示触控控制提示;其 Network Simulator 可模拟 3G / 4G / Wi-Fi / 有线网络,或自定义的入站 / 出站延迟、抖动和丢包,用于测试延迟补偿及加载 / 重试体验。 使用 Controller Emulator 模拟手柄输入。
  • 流式加载:使用 StreamingTargetRadius = 64 进行测试。
  • Studio 中的 DataStore:启用 API 访问,并使用单独的测试 universe 或数据存储名称。

功能发布前的 QA 检查清单

  • 玩家在功能启动后才加入(晚加入玩家)或重生后,功能仍可正常运行。
  • 支持 2 个或更多客户端;服务端状态具有权威性;UI 在所有客户端上更新。
  • 玩家在操作中途离开(交易、购买、回合)时,不会留下损坏的状态或泄漏的表。
  • Remotes 在被垃圾请求或发送格式错误的参数时会被拒绝。
  • 数据可以保存并重新加载(重新加入),包括在不同 place 之间传送。
  • 手机、手柄和键盘均可正常使用;UI 在手机上清晰可读。
  • Output(服务端和客户端)中没有错误或警告。

相关技能

roblox-tooling(CI、Rojo)、roblox-studio-mcp(由 Agent 驱动的游玩测试)、roblox-open-cloud、 roblox-code-review。

评论

支持 Markdown