用于测试 Minetest 核心/引擎库 mineunit

目前可能无法与 Windows 一起使用,因此除非您想帮助解决问题,否则请使用 Linux 或类似的操作系统。

Github 集成可用于在推送新代码时自动执行测试:https ://github.com/marketplace/actions/mineunit-runner

如何使用mineunit

安装 mineunit 并为测试创建 spec 目录:

$ luarocks install --server=https://luarocks.org/dev --local mineunit $ cd ~/.minetest/mods/my_minetest_mod $ mkdir spec

  • spec 通过在目录中创建测试文件来添加测试。
  • *_spec.lua 例如,文件名应与模式匹配mymod_spec.lua
  • 有关可能的规范文件内容,请参见下面的示例。

安装演示规范,替代上述mkdir spec

您可以安装spec 包含简单测试并显示一些您可以做的事情的演示目录。
要将 demo spec cd 安装到您的 mod 目录,必须有init.lua 文件并且不能有现有spec 目录。

  • 运行命令:$ mineunit --demo

为测试定义世界

世界可以通过调用world.layout 包含节点的表来替换,这将重置之前创建的世界布局。您还可以添加更多节点,而无需通过调用world.add_layout 而不是重置先前添加的世界布局world.layout

world.layout({ {{x=0,y=0,z=0}, “default:cobble”}, {{x=0,y=1,z=0}, “default:cobble”}, {{x=0,y=2,z=0}, “default:cobble”}, {{x=0,y=3,z=0}, “default:cobble”}, })

可以使用以下命令添加和删除单个节点world.set_node

world.set_node({x=0,y=0,z=0}, {name=“default:stone”, param2=0})

从世界中删除节点只需将节点设置为nil

world.set_node({x=0,y=0,z=0}, nil)

从世界中删除一切:

world.clear()

使用 Minetest 类和方法

API 尚未完成,但问题正在得到解决,并添加了更多功能,如果您发现问题,请创建问题

  • 要设置节点元数据,只需minetest.get_meta(pos):set_string("hello", "world") 像在 mod 中那样调用即可。
  • 要创建 ItemStack,只需ItemStack("default:cobble 99") 像在 mod 中那样调用即可。
  • 任何其他类似的方式,就像你在 Minetest mods 中做的一样。

示例 mymod/spec/mymod_spec.lua 文件

下面附带了很多无用的东西,只是为了展示如何使用一些 mineunit 功能

-- Load and configure mineunit
require("mineunit")

-- Load some mineunit modules
mineunit("core")
mineunit("player")
mineunit("protection")
mineunit("default/functions")

-- Load some fixtures from spec/fixtures/nodes.lua for tests
-- Skip this if your tests do not need fixtures
fixture("nodes")

-- Load some mymod source files, you wanted to test these right?
-- This will execute init.lua in current directory
sourcefile("init")

-- Maybe we need actual world for test?
-- If world is larger or reused by multiple test specs it might be good
-- idea to put this into spec/fixtures/world.lua and load using fixture("world")
world.layout({
	{{x=0,y=1,z=0}, "mymod:special_dirt"},
	{{x=0,y=0,z=0}, "mymod:special_dirt"},
	{{x=1,y=0,z=0}, "mymod:special_dirt"},
	{{x=0,y=0,z=1}, "mymod:special_dirt"},
	{{x=1,y=0,z=1}, "mymod:special_dirt"},
})

-- Protect some nodes, this will affect outcome of minetest.is_protected calls
mineunit:protect({x=0,y=1,z=0}, "Sam")

-- Create few players
local player1 = Player("Sam", {interact=1})
local player2 = Player("SX", {interact=1})

-- Define tests for busted
describe("My test world", function()

	it("contains special_dirt", function()
		local node = minetest.get_node({x=0,y=0,z=0})
		assert.not_nil(node)
		assert.equals("mymod:special_dirt", node.name)
	end)

	it("allows Sam to dig dirt at y 1", function()
		assert.equals(false, minetest.is_protected({x=0,y=1,z=0}, player1:get_player_name()))
	end)

	it("protects dirt at y 1 from SX", function()
		assert.equals(true, minetest.is_protected({x=0,y=1,z=0}, player2:get_player_name()))
	end)

end)

有用的 Minute API 函数

Mineunit 本身带有一些额外的功能来允许受控的测试执行:

功能 描述
mineunit:set_modpath(name, path) 为命名的 mod 设置 modpath,minetest.get_modpath(name) 然后将报告此路径。
mineunit:set_current_modname(name) 暂时将当前模组名称切换到另一个以测试检查当前模组名称的代码。
mineunit:restore_current_modname() 使用更改后恢复原始 modname mineunit:set_current_modname(name)
mineunit:execute_globalstep(dtime) 执行 Minetest globalstep:将触发注册的 globalsteps、nodetimers、minetest.after 和类似的回调。
mineunit:mods_loaded() 执行用 注册的函数minetest.register_on_mods_loaded(func)
mineunit:execute_shutdown() 模拟服务器关闭事件。
mineunit:execute_on_joinplayer(player, lastlogin) 模拟Player 加入游戏。
mineunit:execute_on_leaveplayer(player, timeout) 模拟Player 离开游戏。
mineunit:execute_on_chat_message(sender, message) 模拟Player 发送聊天消息。
mineunit:execute_modchannel_message(channel, sender, message) Modchannel 消息处理程序。
mineunit:execute_modchannel_signal(channel, signal) Modchannel 消息处理程序。
mineunit:protect(pos, name_or_player) 将位置添加到保护列表以模拟保护而不加载保护模块。
mineunit:get_players() 获取所有已注册玩家,使用鉴权模块时还会返回未加入游戏的玩家。
mineunit:has_module(name) 判断 Mineunit 模块是否已加载。
mineunit:config(key) 读取 Mineunit 配置值。
mineunit:debug(...) verbose 如果选项高于 3 ,则打印到控制台。
mineunit:info(...) verbose 如果选项高于 2 ,则打印到控制台。
mineunit:warning(...) verbose 如果选项高于 1 ,则打印到控制台。
mineunit:error(...) verbose 如果选项高于 0 ,则打印到控制台。
print(...) print 如果选项未禁用,则打印到控制台。
mineunit:destroy_nodetimer(pos) 改用 Minetest 对应物
mineunit:get_modpath(name) 改用 Minetest 对应物
mineunit:get_current_modname() 改用 Minetest 对应物
mineunit:get_worldpath() 改用 Minetest 对应物
mineunit:register_on_mods_loaded(func) 改用 Minetest 对应物
mineunit.export_object(obj, def) 内部使用
mineunit.deep_merge(data, target, defaults) 内部使用
mineunit.registered_craft_recipe(output, method) 内部使用

Mineunit 模块将添加一些功能,例如一些简单的玩家动作模拟等。

矿机模块

核心模块

mineunit("core") 将加载多个模块并为简单的测试设置基本环境,这些模块将与core 模块一起自动加载:

模块名称 描述
世界 提供world 命名空间以允许在测试世界中进行节点操作。
设置 提供Settings 类。core 如果存在,模块还将从 fixtures 目录加载 minetest 配置文件。
元数据 为测试提供元数据和库存操作。
物品堆 提供ItemStack 类。
游戏/常数 Minetest 引擎库。
游戏/物品 Minetest 引擎库。
游戏/杂项 Minetest 引擎库。
游戏/注册 Minetest 引擎库。
游戏/特权 Minetest 引擎库。
常见/misc_helpers Minetest 引擎库。
普通/矢量 Minetest 引擎库。
通用/序列化 Minetest 引擎库。
普通/fs Minetest 引擎库。

建议始终加载core 模块,而不是选择单个自动加载的模块。

附加模块

模块名称 描述
http 提供用于测试使用minetest.request_http_api() .
节点定时器 提供节点定时器功能。
播放器 提供Player 类、特权函数和表单规范函数。metadata 作为依赖加载。
保护 提供简单的节点保护 API 来模拟minetest.is_protected(pos) 行为。
服务器 为 globalstep、player、modchannel 和 chat 提供功能。加载nodetimer ,common/chatcommandsgame/chat 作为依赖项。
体素 提供VoxelManip 类。
授权 提供认证API。
实体 提供 SAO 实体 API。
常用/聊天命令 Minetest 引擎库。
游戏/聊天 Minetest 引擎库。
断言 提供自定义断言,如assert.isPlayer(thing)assert.is_ItemStack(thing)

命令行参数

Usage:
	mineunit [-c|--coverage] [-v|--verbose] [-q|--quiet] [-x|--exclude <pattern>]
	  [--engine-version <version>] [--fetch-core <version>] [--core-root <path>]

Options:
	-h, --help      Display this help message.

	-c, --coverage  Execute luacov test coverage analysis.
	-r, --report    Build report after successful coverage analysis.
	                Currently cannot be combined with --coverage
	-x|--exclude <pattern>
	                Exclude source file patterns from test coverage analysis.
	                Can be repeated for multiple patterns.

	--demo          Install demo tests to current directory.
	                Good way to learn Mineunit or initialize tests for project.

	--core-root <path>
	                Root directory for core libraries, defaults to install path.
	--engine-version <tag>
	                Use core engine libraries from git tag version.
	--fetch-core <tag>
	                Download core engine libraries for tag.
	                This is simple wrapper around `git clone`.

	-v|--verbose    Be verbose, prints more useless crap to console.
	-q|--quiet      Be quiet, most of time keeps your console fairly clean.

Configuration files (in order):
	/etc/mineunit/mineunit.conf
	$HOME/.mineunit.conf
	$HOME/.mineunit/mineunit.conf
	./spec/mineunit.conf

配置文件按顺序检查合并,最后一个配置条目生效。例如,项目配置中的 core_root 将覆盖用户配置中的 core_root。

命令行参数将覆盖所有配置文件条目,除了将被合并的 luacov excludes。表值(luacov 除外)仅在项目配置文件中受支持。

使用 mineunit 的已知项目

有关如何使用 mineunit 以及可以用它做什么的更多示例,请参阅以下项目

Technic Plus:简单、干净和直接的测试。

  • 网络测试https://github.com/mt-mods/technic/tree/master/technic/spec
  • CNC 测试https://github.com/mt-mods/technic/tree/master/technic_cnc/spec
  • GitHub 工作流程https://github.com/mt-mods/technic/blob/master/.github/workflows/mineunit.yml

Metatool:复杂的测试设置。Mineunit 的开发从这里开始。

其他模组