ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

OCaml 编译器测试套件实战:ocamltest 测试驱动完全指南

2026/10/8 7:54:36 拓冰建站 浏览量
OCaml 编译器测试套件实战:ocamltest 测试驱动完全指南 编程语言编译器语言运行时标准库【免费下载链接】ocamlThe core OCaml system: compilers, runtime system, base libraries项目地址https://gitcode.com/gh_mirrors/oc/ocaml点击查看免费下载本文是 OCaml 核心仓库中测试基础设施的权威指南系统讲解如何运行 OCaml 编译器测试套件、如何使用 ocamltest 编写与注解测试以及如何将旧式 makefile 驱动的测试迁移到 ocamltest。读完本文你将掌握(* TEST ... *)注解 DSL、动作action与变量variable机制、参考文件reference的命名规则并能独立编写、调试和批量运行编译器的集成测试。背景从 makefile 到 ocamltestOCaml 编译器的测试套件testsuite由一系列程序组成这些程序会被编译并执行其编译输出与执行输出会被拿来与期望输出expected output逐字比对从而判定测试是否通过。在 ocamltest 出现之前测试由一组 makefile 驱动。这些 makefile 负责编译、运行测试程序并校验输出是否与期望一致。在这种旧架构下某个测试具体应该如何被编译这一信息与测试本身是分离的——它散落在 makefile 的 recipe 中与真正执行编译和运行的指令交织在一起。因此面对一个测试文件很难直接判断它应该如何被编译与运行。ocamltest 正是为解决这一问题而引入的ocamltest/README.md它以测试程序为输入从程序开头的**特殊注释注解块**中推导出编译与运行该测试的确切方式测试相关的元数据被存放在测试文件自身与执行具体任务所需的机制彻底分离而机制被集中到 ocamltest 工具中。ocamltest 本质上是一个**测试驱动test-driver**程序它能够运行测试并向测试基础设施汇报结果。它最初专门为运行 OCaml 编译器的集成测试而设计但其架构具备可扩展性通过插件plugin机制可以扩展出其他类型的测试ocamltest/OCAMLTEST.adoc。设计约束为什么测试驱动本身要用 OCaml 写乍看之下用编译器要编译的语言去写测试该编译器的工具有些古怪——毕竟编译器本身尚未被充分测试因而并不可信。但 OCaml 编译器是**自举bootstrapped**的编译器本身用 OCaml 编写新版本编译器可以由旧版本编译器加新版本的 OCaml 源码构建出来。这意味着编译器至少足够好好到能重新编译自己。因此只要 ocamltest 只使用那些已被用来编译编译器本身的标准库代码就可以认为这些组件比尚未被使用的代码更可信。这正是 ocamltest 只依赖自举过程中用到的标准库部分、且**不依赖任何外部库连随编译器分发的Unix、Str库也不用**的原因。从源码看ocamltest 对系统调用的封装非常克制ocamltest/ocamltest_unix_real.ml与ocamltest/ocamltest_unix_dummy.ml提供一套极小的 Unix 兼容接口而在纯 OCaml 层面则大量使用Ocamltest_stdlibocamltest/ocamltest_stdlib.ml确保运行时只依赖自举所需的最小标准库子集。测试类型与设计取舍ocamltest 的演进背景决定了它的几个看似武断的设计决策不支持单元测试因为 OCaml 编译器的测试套件里本来就没有单元测试以完整程序为测试主体套件主要由完整的程序构成最常规的测试语义就是——程序被编译、被执行编译符合预期且运行返回期望值即视为通过仍需支持各种变体比如只编译不运行带特定选项编译乃至 REPL 测试、调试器测试等完全不同的测试形态。为了把把一个程序变成测试这件事做到最简单ocamltest 设计了一种领域特定语言DSL用于在测试程序顶部的(* TEST *)块中描述测试应如何进行。初始设置两个关键路径ocamltest 启动时只需要知道两件事ocamltest/README.md待测 OCaml 编译器源码的位置该位置在 OCaml 构建时确定默认值可通过环境变量OCAMLSRCDIR覆盖用于构建测试的目录默认值可通过环境变量OCAMLTESTDIR覆盖。以当前仓库源码为准ocamltest/main.ml中的get_test_build_directory_prefix函数实现了这一逻辑ocamltest/main.ml它读取OCAMLTESTDIR环境变量若未设置则回退到当前工作目录下的_ocamltest目录。而在 testsuite 的 make 驱动中该目录被显式设置为测试目录下的_ocamltesttestsuite/MakefileOCAMLTESTDIR $(BASEDIR_HOST)/$(DIR)/_ocamltest。构建测试工具链编写测试的前提是已下载并编译 OCaml 编译器源码——注意编译器无需安装。源码既可以下载归档包也可以直接用 git 克隆后者更适合编写自己的测试。构建方法见 INSTALL.adocWindows 用户另见 README.win32.adoc。在${OCAMLSRCDIR}下运行以下命令即可构建运行测试所需的工具与库make -C testsuite lib tools虽然不强制但强烈建议把ocamltest命令放进PATH这会极大简化测试开发。做法是在PATH中已有的目录如~/bin里创建指向${OCAMLSRCDIR}/ocamltest/ocamltest或其原生版本ocamltest/ocamltest.opt的符号链接。运行测试套件以下命令均假定在OCAMLSRCDIR/testsuite目录下执行。make all运行全部测试make all运行完整的测试套件。按 ocamltest/README.md 的记载这既包括仍在使用 makefile 基础设施的 legacy遗留测试也包括已迁移到 ocamltest 的 new新测试此外还分别提供了make legacy与make new来单独运行这两类测试。在当前仓库的 testsuite/Makefile 中all目标实际由new-without-report与report两步组成前者先调用ocamltest -find-test-dirs tests递归发现所有包含测试的目录再对每个目录运行ocamltest -list-tests逐个执行测试文件后者通过summarize.awk对日志_log做汇总报告。Makefile 中的几个实用入口testsuite/Makefile目标作用all运行全部新测试并输出报告one TESTf/one DIRd/one LISTf运行单个测试文件 / 某个目录 / 某个列表中列出的测试parallel、parallel-foo借助 GNU parallel 并行运行全部或前缀匹配的测试all-foo运行所有以foo开头的测试目录promote TESTf用测试实际输出覆盖参考文件对应-promote选项report打印上一次运行的汇总报告clean删除生成的测试产物手动运行单个测试为了方便可以在PATH中的目录如~/bin放置如下 ocamltest 包装脚本并赋予可执行权限ocamltest/README.md#!/bin/sh TERMdumb OCAMLRUNPARAM /path/to/ocaml/sources/ocamltest/ocamltest $*然后即可直接运行例如ocamltest tests/basic-io/wc.mlocamltest 的输出格式与旧 makefile 风格保持相似这是为了让新旧基础设施的过渡尽可能平滑一旦全部测试都完成迁移这个输出格式才有可能改变。例如 ocamltest/OCAMLTEST.adoc 中展示的运行结果形如... testing hello.ml with 1 (native) passed ... testing hello.ml with 2 (bytecode) passed更详细的测试过程记录在日志文件中路径为${OCAMLTESTDIR}/tests/basic-io/wc/wc.log对应地tests/basic-io/wc.ml展示了如何注解测试文件testsuite/tests/basic-io/wc.ml 中可以看到其 TEST 块只写了arguments wc.ml;一行。日志文件名由主程序生成在 ocamltest/main.ml 中日志被写到测试构建目录下、以测试文件主名加.log后缀命名的文件。想看哪些测试已经迁移到 ocamltest可以执行find tests -name *ocamltests* | xargs cat这会列出所有已迁移测试目录下ocamltests文件的内容可作为理解 ocamltest 能力的起点。ocamltest 命令行选项从 ocamltest/options.ml 可以看到 ocamltest 支持的全部命令行选项选项含义-e日志输出到 stderr 而不是文件-promote用测试输出覆盖参考文件实验性、不稳定-show-actions列出所有可用的动作action-show-tests列出所有可用的测试含默认运行标记-show-variables列出所有可用的变量-show-timings显示每个测试文件消耗的墙钟时间-timeout 秒设定每条命令的最大执行时间默认见 Makefile 中TIMEOUT ? 600即 10 分钟testsuite/Makefile-find-test-dirs 目录递归查找包含测试的目录main.ml中实现ocamltest/main.ml-list-tests 目录列出指定目录中的测试文件ocamltest/main.ml-keep-test-dir-on-success测试通过后也保留构建目录及测试产物对应make ... KEEP1-color auto\|always\|never控制编译器消息的颜色也可用OCAML_COLOR环境变量设置注意-translate、-compact、-keep-lines、-keep-chars等选项已在 OCaml 5.6 中移除ocamltest/options.ml。另外OCAMLTEST_SKIP_TESTS环境变量可指定需要跳过的测试文件列表ocamltest/main.mlMAKE环境变量用于指定调用的 make 命令testsuite/Makefile 中会把MAKE$(MAKE)传给 ocamltest。编写第一个测试Hello, world!下面把经典的 Hello, world! 程序变成一个 ocamltest 测试完整走一遍流程ocamltest/OCAMLTEST.adoc。第 1 步写测试程序并添加 TEST 块。假设文件为hello.ml(* TEST *) let _ print_endline Hello, world!第 2 步声明期望输出。期望编译过程静默无输出这是默认行为若编译产生输出反而会导致测试失败期望程序执行输出一行。把这一行写入参考文件hello.referenceHello, world!第 3 步运行测试ocamltest hello.ml输出类似... testing hello.ml with 1 (native) passed ... testing hello.ml with 2 (bytecode) passed同时会在当前目录创建一个_ocamltest目录用于存放测试产物。第 4 步纳入套件。若希望该测试随编译器测试套件自动运行把hello.ml与hello.reference移到testsuite/tests之下的某个目录比如newtest然后在testsuite目录执行make all即可。测试期间到底发生了什么仅从 ocamltest 的输出只能看到运行了bytecode和native两个测试且都通过——这对测试基础设施来说已经足够但对使用者远远不够。因此 ocamltest 会把更多细节写入每个测试专属的日志文件即_ocamltest/hello/hello.log。ocamltest 会为每个被测文件创建一个专属目录并把该文件测试产生的所有文件放入其中直接放入或放入其子目录当同一测试需要以不同选项或不同编译器多次编译时会使用子目录。理解日志之前需要先记住一个事实OCaml 实际包含四个编译器——ocamlc.byte与ocamlc.opt字节码编译器的字节码版与原生版以及ocamlopt.byte与ocamlopt.opt原生编译器的字节码版与原生版。因此测试字节码编译器实际上涉及测试两个编译器测试原生编译器同理。日志的开头是这样的Specified modules: hello.ml Source modules: hello.ml第一行列出测试包含的模块即modules变量指定的模块第二行几乎相同但如果某些模块带有独立的接口文件.mli它们也会出现在这里——对每个指定的.ml文件ocamltest 会自动检查是否存在对应的.mli并加入待处理列表无需用户显式指定。日志的其余部分可分为结构非常相似的两段native测试一段、bytecode测试一段。以bytecode测试为例它由9 个动作组成。这里引入 ocamltest 的术语动作action任何可以pass通过、skip跳过或fail失败的东西测试test一系列动作的序列。运行测试就是依次运行每个动作直到全部动作执行完毕或某个动作返回fail/skip最后运行的动作的返回值就是整个测试的结果。bytecode测试的 9 个动作与 ocamltest/ocaml_tests.ml 中的定义一一对应setup-ocamlc.byte-build-env为ocamlc.byte创建构建环境——在测试专属目录下新建一个专用目录并放入后续动作所需的文件根据操作系统支持情况文件会被符号链接或从测试源码目录复制ocamlc.byte以各种方式调用ocamlc.byte编译并链接测试程序具体行为取决于 ocamltest 的变量check-ocamlc.byte-output若存在参考文件则比对编译器输出不存在参考文件则意味着期望编译器输出为空一旦有输出该动作进而整个bytecode测试即失败run程序编译成功后运行它把标准输出与标准错误保存到文件check-program-output把程序输出与参考文件即hello.reference比对——可以试着改动参考文件观察整个测试如何因此失败 5 之后是ocamlc.opt编译器对应的四个动作setup-ocamlc.opt-build-env动作 1 在ocamlc.opt下的对应物ocamlc.opt用ocamlc.opt编译测试程序check-ocamlc.opt-output同动作 3compare-bytecode-programs不运行程序而是把ocamlc.opt生成的二进制与动作 2 中ocamlc.byte生成的二进制做逐字节比对要求两者完全相同。这种检查看似苛刻但历史上确实借此发现过编译器中的微妙 bug。从源码看bytecode测试的动作序列还有平台相关的分支在 Windows 上且原生编译器可用时会跳过ocamlc.byte环节直接使用opt_build在非 Windows 且存在--with-relative-libdir配置时会跳过compare-bytecode-programs因为此时ocamlc.opt与ocamlrun位于构建树的不同层级无法可靠比较ocamltest/ocaml_tests.ml。native测试的结构类似动作依次为setup-ocamlopt.byte-build-env、ocamlopt.byte、check-ocamlopt.byte-output、run、check-program-output、setup-ocamlopt.opt-build-env、ocamlopt.opt、check-ocamlopt.opt-output并且仅在配置了原生编译器时运行否则整个测试直接skipocamltest/ocaml_tests.ml。定制默认测试变量与参考文件动作进而测试的精确行为取决于变量变量的值可以在(* TEST ... *)块中调整。在 ocamltest 中所有变量的值都是字符串。向编译器传递标志flags假设hello.ml修改为打开Format模块但未使用(* TEST *) open Format let _ print_endline Hello, world!程序依然能通过默认测试但它不再是最小版本。OCaml 有专门检测未使用open的警告warning 33默认关闭。我们可以把这个版本加入套件目的不是验证编译运行而是验证编译器确实触发期望的警告。做法修改测试块(* TEST flags -w 33; *)由于现在编译器输出非空需要把期望输出存到hello.compilers.reference文件与hello.ml、hello.reference并列。可以先运行ocamltest hello.ml——检查编译器输出的动作当然会失败但会给出编译器实际输出文件的路径从而可以核对并移动为参考文件ocamltest hello.ml cat _ocamltest/hello/ocamlc.byte/ocamlc.byte.output mv _ocamltest/hello/ocamlc.byte/ocamlc.byte.output hello.compilers.reference之后再运行ocamltest hello.ml所有测试通过。这里有两个要点flags变量给所有编译器传递额外标志另有ocamlc_flags与ocamlopt_flags可分别只给字节码或原生编译器传参本例中四个编译器的输出相同因此一个参考文件就够。但当输出是后端相关取决于编译目标是字节码还是原生码甚至编译器相关时ocamltest 会按名称依次查找更具体的参考文件查找顺序参考文件命名适用1hello.ocamlc.byte.reference仅ocamlc.byte特有2hello.ocamlc.referenceocamlc.byte与ocamlc.opt共有3hello.compilers.reference所有编译器共有4无文件期望编译器输出为空使用辅助模块modules把问候逻辑抽取到独立模块greet.ml并配上接口greet.mlilet greet guest Printf.printf Hello, %s!\n guestval greet : string - unithello.ml重写为(* TEST modules greet.ml; *) let _ Greet.greet world删掉此前用于测试警告的hello.compilers.reference后运行 ocamltest日志开头两行会变成Specified modules: greet.ml hello.ml Source modules: greet.mli greet.ml hello.ml第一行表明modules变量被采纳第二行里greet.mli出现在greet.ml之前——这是 ocamltest 自动加入的因为它被识别为某指定模块的接口。小结若测试由多个模块构成只需在modules变量中按链接顺序列出它们的实现文件主测试程序的实现是隐式的无需列出接口文件会被自动补上。链接库directories与libraries假设要用下面的程序验证Str库的正则表达式行为let hello_re Str.regexp ^Hello, .!$ let hello_str Hello, world! let _ if not (Str.string_match hello_re hello_str 0) then begin Printf.eprintf There is a problem!\n; exit 2 end程序一切正常时静默退出、出错时才向 stderr 打印消息因此无需额外配置空输出检查。但编译链接它需要指向正确目录的-I选项以及链接时正确的库文件名。ocamltest 提供了directories与libraries变量它会自动为每个目录加-I、并根据目标是字节码还是原生程序自动选择正确的库文件。注解如下(* TEST directories ${ocamlsrcdir}/otherlibs/str ; libraries str ; *)这里首次遇到 DSL 的两个语法点${variable}字符串中的变量展开记号与 bash 等 shell 的语义一致运算符把值拼接concatenate到变量。注意foo bar等价于foo ${foo}bar而不是foo ${foo} bar。也就是说不会像 make 那样隐式插入空格——空格必须显式写在字符串里。这正是上面注解中directories、libraries的加值两侧都带空格的原因这些空格是必需的否则加值会与变量原有内容粘连而被误解。环境修饰符environment modifiersinclude若大量测试都要链接Str逐条重复上述两行会难以维护。ocamltest 提供了更优雅的机制——环境修饰符environment modifier一个把若干变量定义打包起来的对象可在测试块中一次性引入。修饰符定义在 ocamltest 自身通过include指令使用(* TEST include str; *)从 ocamltest/tsl_parser.mly 可以看到 DSL 中INCLUDE identifier与SET/UNSET语句的语法定义include是首等的环境语句。测试树、块与变量作用域有些测试需要限定操作系统。比如让测试只在 Unix 平台上运行(* TEST unix; { bytecode; } { native; } *)从这个例子可以看出测试的组织方式测试被组织成一棵嵌套块的树。每个块以花括号开始内含一组按顺序执行的测试与环境语句块再包含若干彼此独立执行的子块各自环境独立且互不因兄弟块成败而受影响。这里bytecode与native是两个子测试只有unix测试通过时才会启动若unix失败或跳过它们根本不会开始。由此可知最小的测试块(* TEST *)实际等价于(* TEST { bytecode; } { native; } *)一个常见误区是认为下面的写法会先执行unix测试再执行默认测试(* TEST unix; *)并非如此。默认测试只有在测试块中完全没有测试语句时才会被考虑。一旦出现了任何测试语句默认测试就被完全忽略必须显式地写明要运行哪些测试。因此正确的写法是本节开头展示的带花括号形式。从 ocamltest/main.ml 可以看到这一语义在源码中的实现当解析出的 TSL 语法树为空时ocamltest 才把默认测试展开为子块树Tests.default_tests()即bytecode与native。花括号还明确了变量赋值的作用域一次赋值会修改变量其效力持续到所在块的其余部分以及所有子块除非在子块中被覆盖。例如(* TEST foo abc; { bar def; test1; { baz hij; subtest1; } { subtest2; } } { test2; } *)foo的定义对所有测试可见bar的定义对所有测试可见唯test2除外baz的定义只对subtest1可见。DSL 中的逻辑组合与set/unsetDSL 的抽象语法ocamltest/tsl_ast.mli定义了环境语句赋值、追加、include、unset与语句的组合子not、and、or||、if ... then ... else ...动作还可以带with修饰符。语法层面ocamltest/tsl_parser.mly支持IF/THEN/ELSE、AND/OR/NOT、括号分组与花括号子块测试块既可以用 OCaml 风格注释(* TEST ... *)也可以用 C 风格注释书写。另外还可以在测试头中显式设置/取消环境变量(* TEST set VARIABLE_NAMEvalue; *)引号是必需的以及(* TEST unset VARIABLE_NAME; *)确保变量在测试运行时未被设置。其他常用测试toplevel、expect 与 scripttoplevel与expect测试顶层交互toplevel与expect两个测试都用于验证 OCaml 顶层toplevel对用户输入的反应区别在于期望输出的指定方式与可测范围toplevel与编译器测试精神一致期望输出存放在独立文件中它调用真实的 OCaml 顶层进程适合测试顶层以文件而非终端作为输入等高级行为expect输入与期望输出写在同一文件中、彼此靠近它把 OCaml 顶层作为库来使用而非作为外部程序调用因此测的不是完整真实的顶层但对语言特性的测试完全够用也是大多数场景所需要的。expect测试示例(* TEST expect; *) type point { x : int; y : int };; [%%expect{| type point { x : int; y : int; } |}];;TEST 块之后的第一行是输入短语[%%expect{| ... |}];;之间的内容是对应的期望输出。expect测试还可用于验证-principal命令行标志下的输出此时期望输出写在|}, Principal{|块中。从 ocamltest/ocaml_tests.ml 看expect测试的动作序列是setup_simple_build_env、run_expect、check_program_output。script把测试写成 shell 脚本如果需要的测试 ocamltest 没有提供且该测试只针对个别文件、不值得写进 ocamltest 本身可以把它写成 shell 脚本用script测试来运行。脚本名由script变量指定脚本运行时ocamltest 中定义的所有变量都会被导出为环境变量脚本用退出状态汇报结果还可以向一个专属文件写内容以修改环境或说明通过/跳过/失败的原因。用脚本测试我们的hello.ml示例(* TEST script ${test_source_directory}/faketest.sh; script; *) let _ print_endline Hello, world!对应的faketest.sh需可执行#!/bin/sh exit ${TEST_PASS}TEST_PASS、TEST_FAIL、TEST_SKIP是 ocamltest 导出的三个退出码变量定义见 ocamltest/builtin_variables.ml。让脚本优雅地失败#!/bin/sh echo Why should this pass in the first place ${ocamltest_response} exit ${TEST_FAIL}再次运行 ocamltest 会得到... testing hello.ml with 1 (script) failed (Why should this pass in the first place)此外脚本可以向${ocamltest_response}文件写入如下格式的行分别用于设置、追加、取消环境变量variablestring variablestring -variable内置变量与动作清单ocamltest 内置变量的完整列表可用ocamltest -show-variables查看内置及 OCaml 专属动作/测试列表用ocamltest -show-actions/-show-tests查看。核心内置变量ocamltest/builtin_variables.ml包括变量含义arguments传给被执行程序/脚本的参数如wc.ml测试中的arguments wc.ml;cwd切换当前工作目录只用于切换不会被更新commandline指定某个工具的命令行exit_status期望的程序退出状态file待检验是否存在的文件output保存程序执行输出的位置program/program2ocamlc.byte/ocamlopt.byte与ocamlc.opt/ocamlopt.opt产出的程序名promote置为true时用测试输出覆盖参考文件reason让测试汇报通过/跳过/失败的原因reference程序输出应与之比对的文件路径skip_header_lines/skip_header_bytes比对程序输出与参考文件时跳过的行数/字节数script要运行的外部脚本src/dst待复制的文件/目录及其目标位置stdin/stdout/stderr默认的标准输入输出subdirectories从测试源码目录递归复制到构建目录的子目录test_file含测试规格的文件名test_source_directory测试源文件所在目录test_build_directory/test_build_directory_prefix测试构建目录及其前缀TEST_PASS/TEST_SKIP/TEST_FAIL脚本汇报成功/跳过/失败的退出码timeout每条命令的最大执行时间秒run_can_skip置为true允许run动作返回跳过状态ocamltest_response钩子hook回传信息的文件ocamltest_log当前测试的日志文件路径MAKE调用 make 所用的命令dev_null/dev/null的路径内置动作ocamltest/builtin_actions.ml除pass/skip/fail/cd/dumpenv等基础动作外还包括大量条件判定动作hasunix、libunix、libwin32unix、hassysthreads、hasstr、multicore、has_reserved_header_bits等用于在特定平台特性/库可用时才继续测试。OCaml 专属测试ocamltest/ocaml_tests.ml包括bytecode、native默认运行、toplevel、toplevel.opt原生顶层 ocamlnat、expect、ocamldoc、asmgen生成汇编并用 C 编译器链接成可执行文件等。迁移指南从 makefile 到 ocamltest在开始迁移前建议先在testsuite目录运行make new了解当前新测试的数量。每迁移n个测试后再运行make new新测试数量应正好增加n。OCaml 的测试套件按目录组织每个目录包含一个或多个测试每个测试由一个或多个文件组成。因此目录是能够迁移的最小单位。查看还有哪些目录待迁移find tests -name Makefile即testsuite/tests下仍含 Makefile 的子目录就是待迁移目录。假设要迁移目录foo阅读foo/Makefile弄清该目录包含多少测试、如何编译。如果 makefile 只是 include 其他 makefile 而未定义任何变量说明编译运行这些测试无需特殊处理用旧框架实际运行该目录的测试观察确切的编译与执行方式make --trace DIRtests/foo建议把输出记录下来备用。为每个测试的主文件添加测试块即形如(* TEST Optional variable assignments and tests *)的注释。例如测试主文件为foo.ml且使用模块m1.ml、m2.ml(* TEST modules m1.ml m2.ml; *)若测试是单个foo.ml且需在顶层运行(* TEST toplevel; *)若该测试有两个参考文件、其中一个名字含 principal意味着要用顶层分别在有/无-principal选项下测试(* TEST toplevel; include principal; toplevel; *)以星号开头的行指明要运行哪些测试若未指定任何测试则使用默认启用的测试——大致上就是分别用字节码与原生码编译并运行测试程序。运行 ocamltest 验证对注解后的测试运行ocamltest通过则罢失败则查看日志文件找出原因并调整直到全部通过。调整工作大部分是重命名参考文件与更新其内容。注意参考文件分为两类编译器输出参考文件与程序输出参考文件。核对迁移正确性把 ocamltest 日志中用于编译程序的命令与make --trace得到的命令做比对。注意用于比对结果与期望值的命令不会出现在 ocamltest 日志中。创建ocamltests文件注意末尾的复数 s把所有已注解的测试文件名逐行写入一个文件一行。删除旧 Makefile 并验证git rm该 Makefile然后在testsuite目录运行make new确认新测试数量如预期增加。总结ocamltest 把测试如何编译运行的元数据从分散的 makefile 集中到测试文件开头的(* TEST *)注解块中让测试自描述、自包含。其核心模型——由动作组成的测试树、字符串类型的变量、/${var}/include等 DSL 语法、分级命名的参考文件——覆盖了从编译并运行程序到顶层交互、expect、外部脚本的各类测试形态并已完全接管了 OCaml 编译器测试套件的自动化运行。掌握了本文的注解语法、默认测试的 9 步动作序列与参考文件查找规则你既可以快速为编译器的新行为编写回归测试也可以把历史 makefile 测试平滑迁移到 ocamltest 框架之下。赞分享编程语言编译器语言运行时标准库【免费下载链接】ocamlThe core OCaml system: compilers, runtime system, base libraries项目地址https://gitcode.com/gh_mirrors/oc/ocaml点击查看免费下载相关推荐OSRM Backend 测试套件实战指南Boost 单元测试与 Cucumber 场景驱动测试OSRM Backend 测试套件实战指南Boost 单元测试与 Cucumber 场景驱动测试 导读 本文是 OSRMOpen Source Routin后端GIS图计算Peewee 安装与测试完全指南从 PyPI 到源码编译、C 扩展与测试套件实战Peewee 安装与测试完全指南从 PyPI 到源码编译、C 扩展与测试套件实战 Peewee 是一个轻量而富有表现力的 Python ORM支持 Post后端ORM数据库ILSpy 反编译器测试套件完全指南矩阵式测试模型、测试种类与新增用例实践ILSpy 反编译器测试套件完全指南矩阵式测试模型、测试种类与新增用例实践 本文是 ILSpy 开源仓库中 ICSharpCode.Decompiler.Te逆向工程开发工具桌面应用上一篇从论文到代码pixelNeRF论文核心公式的PyTorch实现详解下一篇通义千问 Qwen 开源大模型一份写给技术决策者的企业级部署评估指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考