尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Godot GDScript 测试套件实战解析:集成测试脚本、输出对比与 Autocompletion 测试机制

Godot GDScript 测试套件实战解析:集成测试脚本、输出对比与 Autocompletion 测试机制 Godot GDScript 测试套件实战解析集成测试脚本、输出对比与 Autocompletion 测试机制【免费下载链接】godotGodot Engine – Multi-platform 2D and 3D game engine项目地址: https://gitcode.com/GitHub_Trending/go/godot本文以 Godot 仓库中的 GDScript 测试说明文档 为主体完整讲解modules/gdscript/tests/目录下两类测试的组织方式一是scripts/中的 GDScript 集成测试源码文件 期望输出文件二是scripts/completion中的 GDScript 代码补全测试.gd用例 .cfg期望配置。读完本文你可以理解 Godot 如何在不启动完整编辑器的情况下对 GDScript 的解析、类型检查、编译、运行及编辑器补全结果做自动化断言并知道如何按规范新增测试用例。一、测试目录结构与配套环境GDScript 模块的测试代码位于 modules/gdscript/tests/其核心文件分工如下文件职责gdscript_test_runner.h / gdscript_test_runner.cpp集成测试运行器扫描scripts/目录、执行脚本并比对输出test_completion.hAutocompletion 测试运行器仅在TOOLS_ENABLED下编译test_gdscript.h / test_lsp.h分阶段测试入口Tokenizer / Parser / Compiler / Bytecode / LSPscripts/测试脚本与期望输出含analyzer/、parser/、runtime/、completion/、lsp/等子目录project.godot测试专用工程配置其中 project.godot 开头明确写着; This is not an actual project. ; This config only exists to properly set up the test environment. ; It also helps for opening Godot to edit the scripts, but please dont ; let the editor changes be saved.它不是真正可运行的工程而是为测试环境提供ProjectSettings如test_input_action输入动作。运行器初始化时会调用ProjectSettings::setup(p_base_path, ...)加载该目录并初始化 GDScript 语言与 Autoload见 gdscript_test_runner.cpp。二、集成测试脚本文件 输出文件README 第一部分说明scripts/目录中的集成测试以“GDScript 文件 输出文件”的形式存在。从源码可以确认其完整工作机制。2.1 测试执行管线每个测试脚本必须包含名为test的函数运行器将test_function_name固定为StringName(test)见 gdscript_test_runner.cpp。GDScriptTest::execute_test_code()gdscript_test_runner.cpp按如下顺序处理每个脚本加载读取脚本源码若为二进制 token 模式则用GDScriptTokenizerBuffer::parse_code_string(code, COMPRESS_ZSTD)压缩为 token 缓冲再set_binary_tokens_source()解析GDScriptParser::parse()失败则记录第一条解析错误后续错误可能是级联错误类型检查GDScriptAnalyzer::analyze()错误按start_line排序后逐行输出为 ERROR at line N: ...编译GDScriptCompiler::compile()运行ClassDB::instantiate()创建宿主对象、set_script()挂载脚本然后通过instance-callp(test, ...)调用测试函数。执行过程中通过add_print_handler()/add_error_handler()接管标准输出与错误输出print()的内容逐行追加到结果中脚本错误则格式化为 类型: 错误信息 at 相对路径:行号 on 函数()的形式仅ERR_HANDLER_SCRIPT类型附带文件/行号以保证输出跨平台稳定。最终的判定逻辑是全文比对实际输出去掉首尾空白、末尾补一个换行以适配 CI 静态检查与同名.out文件内容逐字符比较见 check_output()。2.2 测试结果状态码GDScriptTest定义了 6 种状态写入输出文件首行可直观区分脚本卡在哪一阶段gdscript_test_runner.h状态含义GDTEST_OK成功执行到运行阶段GDTEST_LOAD_ERROR源码加载失败或找不到test()函数GDTEST_PARSER_ERROR解析阶段失败随后输出第一条解析错误GDTEST_ANALYZER_ERROR类型检查阶段失败输出按行排序的错误列表GDTEST_COMPILER_ERROR编译阶段失败GDTEST_RUNTIME_ERROR运行期发生脚本错误2.3 文件名约定与构建差异目录扫描逻辑 make_tests_for_dir() 实现了若干文件名约定编写集成测试时必须遵守*.notest.gd被完全跳过用于存放测试辅助代码例如 utils.notest.gd 中定义的Utils类提供了静态check()断言函数并打印失败时的调用栈供运行期测试复用*.norun.gd只验证“解析 类型检查 编译”三个阶段不要求存在test()函数因此不执行运行期测试gdscript_test_runner.cpp*.bin.gd同一脚本会先以文本 tokenizer 模式跑一遍再强制以TOKENIZER_BUFFER二进制 token模式跑一遍两种模式共享同一个.out期望文件*.textonly.gd在启用--use-binary-tokens的测试运行中会被跳过首行为#debug-only的脚本仅在 release 构建DEBUG_ENABLED未定义中被跳过。调试/发布构建的行为差异还包括警告处理Debug 构建中运行器会把所有GDScriptWarning的级别强制设为Warn便于测试原本默认是 Error 的警告但UNTYPED_DECLARATION与INFERRED_DECLARATION两类默认保持关闭若某个脚本需要测试这两类警告可在源码中加入注释# enable UNTYPED_DECLARATION或# enable INFERRED_DECLARATION运行器会据此动态打开对应设置gdscript_test_runner.cpp 与 L545-L555警告统一以~~ WARNING at line N: (警告名) 消息的格式进入输出在 release 构建中期望文件里所有以~~开头的行会被 strip_warnings() 剔除后再比对从而同一份.out文件能同时适配两类构建。2.4 重新生成期望输出集成测试采用“黄金输出golden output”模式当 GDScript 行为变化导致输出变化时可用命令行参数重新生成全部.out文件。handle_cmdline() 支持的用法为--gdscript-generate-tests [测试目录路径]省略路径参数时默认作用于modules/gdscript/tests/scripts追加--print-filenames可逐个打印正在处理的文件名生成模式generate_outputs()下不要求.out文件已存在执行完每个脚本后将实际输出写入同目录的脚本名.out。三、Autocompletion 测试➡ 光标标记与 .cfg 期望文件README 第二部分也是本文档的重心说明scripts/completion目录存放 GDScript 代码补全测试每个用例至少包含一个.gd文件被测代码和一个.cfg文件期望结果与配置。3.1 光标位置标记➡在 GDScript 文件中字符➡U27A1表示触发补全时的光标位置。由于该字符不是合法 GDScript 词法符号且补全往往发生在代码不完整时这些脚本本身并不可解析。运行器test_completion.h的处理方式是读取脚本后把第一个➡0x27A1替换为哨兵字符 0xFFFF使用0x27A1而非 0xFFFF 是为了让文件对人类可读并要求脚本中必须存在该哨兵否则CHECK(location ! -1)失败当测试需要场景owner 节点时删除包含哨兵字符的整行重新reload()脚本并set_script()挂到节点上因此除该行外脚本必须合法——必要时可补一个pass语句正由于脚本由运行器挂载到 owner 节点上脚本不应再通过场景文件加载。3.2 配置文件[input]段测试环境配置.cfg是标准 INI 风格配置用ConfigFile加载。[input]段的完整键位如下与 README 一一对应并补充了源码中的取值细节键类型默认值作用csbooleanfalse为true时在非 C#Mono构建中跳过该测试。源码对应#ifndef MODULE_MONO_ENABLED下的判断test_completion.huse_single_quotesbooleanfalse为本次测试设置编辑器选项text_editor/completion/use_single_quotesadd_node_path_literalsbooleanfalse为本次测试设置编辑器选项text_editor/completion/add_node_path_literalsadd_string_name_literalsbooleanfalse为本次测试设置编辑器选项text_editor/completion/add_string_name_literalssceneString无指定补全时打开的场景未设置时运行器会查找与 GDScript 文件同基名的.tscn两者都没有时补全按“无场景打开”处理test_completion.hnode_pathString.场景根节点持有当前脚本的节点在场景中的路径test_completion.h3.3 配置文件[output]段期望结果断言键类型说明includeArray结果中应当出现的建议列表无序。每个条目是一个字典支持display、insert_text、kind、location四个键对应代码中建议结构ScriptLanguage::CodeCompletionOption的字段。运行器只测试条目中显式给出的键因此多数情况下只写display即可excludeArray结果中不应出现的建议条目格式与include相同call_hintString期望的调用提示call hintforcedboolean补全是否预期强制打开补全窗口关键规则是只针对[output]中显式给出的条目做断言“Tests will only test against entries in[output]that were specified”。这与源码实现一致match_option() 对字典里缺失的键取实际值参与比较即视为“不校验”而call_hint/forced的缺省值就是运行器实际返回的值。校验流程test_directory()调用GDScriptEditorLanguage::complete_code(code, res_path, owner, options, forced, call_hint)得到建议列表后先检查任何结果项不得命中exclude命中则报 “Autocompletion suggests illegal option”再把include中每一项逐一从实际结果中“认领”未全部认领则CHECK(include.is_empty())失败最后比对call_hint与forced。3.4 一个完整用例参数补全play_typed以 scripts/completion/argument_options/play_typed.gd 为例脚本内容为extends Node onready var anim: AnimationPlayer $AnimationPlayer func test(): anim.play(➡) pass➡位于anim.play(的参数位置。配套的 play_typed.cfg 为[input] sceneres://completion/argument_options/argument_options.tscn [output] include[ {display: \bounce\}, ]含义是补全时加载argument_options.tscn场景其中提供AnimationPlayer节点且由于anim是明确标注为AnimationPlayer类型的变量play()的第一个字符串参数应触发枚举/字面量建议结果中必须出现display为bounce的条目。argument_options/目录下还有play_untyped.gd、play_inferred.gd、connect.gd等用例分别覆盖参数类型为未标注、可推断、以及信号连接等场景正是 README 所要求“同一行为在多个上下文中反复测试”的实例。3.5 补全测试的初始化流程整个补全测试套件由 doctest 套件[Modules][GDScript][Completion]下的用例[Editor] Check suggestion list驱动test_completion.h流程为将text_editor/completion/use_single_quotes复位为false保证起点状态一致init_language(modules/gdscript/tests/scripts)加载测试工程配置并初始化 GDScript 语言setup_global_classes()递归扫描scripts/completion目录把带class_name的 GDScript 注册为全局类并检查重名冲突test_completion.h。completion/目录下的 class_a.notest.gd、class_b.notest.gd等辅助类即通过此机制进入全局类索引从而被补全测试引用test_directory()递归遍历每个.gd用例跳过*.notest.gd按 3.2/3.3 节规则执行断言结束后memdelete(scene)释放实例化的场景finish_language()收尾。四、编写 Autocompletion 测试的实践准则README 最后强调“为避免边缘用例失败同一行为需要多次测试”并给出两类必查维度。覆盖所有可能的类型来源——针对被测试行为适用的每一种类型都要测一遍BUILTIN内置类型NATIVE原生类GDScript 类含带class_name的与preload引入的两种形式C# 类作为所有其他语言绑定的代表同样区分class_name与preload两种形式Autoload 单例。README 还特别提醒对最后几类测试SCRIPTGDScript 提供与CLASS可由 C# 提供两种来源即可不要依赖“Autoload 一定是 SCRIPT 类型”因为这一行为未来可能变化。覆盖可能的上下文——补全位置可能出现在程序的不同位置例如类成员变量的初始化表达式中语句块suite内直接书写语句块内的赋值语句中作为函数调用的参数如play_typed.gd所示。从scripts/completion/的实际目录布局也能印证这些准则已被落实types/ 下按local/、member/、hints/划分上下文assignment_options/、argument_options/、index/、filter/、get_node/、global_enum/、enum_values_in_match/等目录分别对应不同的补全触发场景types/中则覆盖本地变量、成员变量与类型提示的差异。五、如何查看与运行这些测试结合源码中可确认的信息运行这些测试的途径是Autocompletion 测试随测试构建test build需TOOLS_ENABLED使 test_completion.h 参与编译一起通过 doctest 框架执行用例标签为[Modules][GDScript][Completion]集成测试由 test_gdscript.h 定义的TEST_TOKENIZER、TEST_TOKENIZER_BUFFER、TEST_PARSER、TEST_COMPILER、TEST_BYTECODE各阶段分别驱动统一入口为GDScriptTests::test(TestType)内部构造GDScriptTestRunner其--use-binary-tokens构造参数对应二进制 token 模式重新生成期望输出在测试可执行文件的命令行中传入--gdscript-generate-tests可选指定测试目录与--print-filenames运行器会把每个脚本的实际输出写回对应的.out文件。需要说明的适用前提警告相关输出~~ WARNING ...行仅在调试构建中产生发布构建下会自动剔除cs键标记的 C# 用例只有在启用 Mono 模块的构建中才会真正执行。六、小结modules/gdscript/tests/README.md用简短篇幅定义了 Godot 中 GDScript 的两种自动化测试范式集成测试以“脚本 黄金输出文件”验证解析、类型检查、编译与运行全链路并通过GDTEST_*状态码定位失败阶段Autocompletion 测试则以➡光标哨兵加.cfg期望文件对建议列表、call hint 与强制补全行为做精确断言[input]段的 6 个配置键可精细控制编辑器选项与场景上下文。两者的实现分别落在 gdscript_test_runner.cpp 与 test_completion.h 中文件名约定.notest.gd、.norun.gd、.bin.gd、#debug-only、警告开关机制与--gdscript-generate-tests再生成流程共同构成了一套对构建类型稳健、可离线复现的 GDScript 质量保障体系。【免费下载链接】godotGodot Engine – Multi-platform 2D and 3D game engine项目地址: https://gitcode.com/GitHub_Trending/go/godot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表