Apache Arrow MATLAB 接口测试指南:runtests 执行、测试编写规范与代码覆盖率实践
2026/9/14 22:39:26 网站建设 项目流程

Apache Arrow MATLAB 接口测试指南:runtests 执行、测试编写规范与代码覆盖率实践

【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow

本文基于 Apache Arrow 仓库中的 MATLAB 接口测试指南 展开,系统讲解如何为matlab目录下的 Arrow MATLAB 接口编写、组织和运行单元测试:包括使用runtests命令执行单个测试文件或整个测试目录、遵循 MATLAB 类基单元测试框架(matlab.unittest.TestCase)编写符合项目规范的测试用例、理解"源码-测试平行目录"的测试组织规则,以及通过ReportCoverageFor参数检查代码覆盖率。读完后,你可以独立完成一次针对 MATLAB 接口的完整测试提交流程,并确保 CI 工作流(.github/workflows/matlab.yml)在合并前通过。

一、背景与前置条件

Apache Arrow 的 MATLAB 接口(matlab目录)将 Arrow C++ 库的列式内存能力暴露给 MATLAB 用户,其 API 采用arrow.*命名空间(如arrow.array.StringArrayarrow.tabular.Table)。为验证接口行为符合预期(例如 MATLAB 数组与 Arrow 数组之间的双向转换),需要维护一套覆盖数组、类型、IO、表格等模块的单元测试,这些测试全部位于 matlab/test 目录下。

按照官方测试指南(testing_guidelines_for_the_matlab_interface_to_apache_arrow.md),在本地运行 MATLAB 接口测试前,需要安装以下软件:

  1. MATLAB(运行覆盖率报告时要求R2023b 或更高版本);
  2. 已构建好的 Apache Arrow MATLAB 接口(即matlab目录对应的编译产物)。

MATLAB 接口的整体设计可参考同目录下的 matlab_interface_for_apache_arrow_design.md,其中描述了arrow.Arrayarrow.RecordBatcharrow.Table等核心 API 以及 MATLABmissing值自动转换为 ArrowNULL的行为约定——这些约定正是测试需要验证的对象。

二、本地运行测试:runtests 命令

本地测试的标准流程是:启动 MATLAB,cdmatlab/test下存放目标测试文件的目录,然后调用runtests命令。指南给出两种常用形态:

% 运行单个测试文件 >> runtests(testFileName) % 例如:runtests("tArray.m") % 递归运行某个测试目录下的所有测试 >> runtests(testFolderName, IncludeSubfolders = true) % 例如:runtests('matlab\test', IncludeSubfolders = true)

仓库 matlab/README.md 中也给出了同样的操作方式:在arrow/matlab目录下启动 MATLAB 后执行

>> runtests("test", IncludeSubFolders=true);

从源码结构看,matlab/test目录按被测模块划分为arrow/array(各类数组如 tStringArray.m)、arrow/type(类型与 traits)、arrow/io(CSV、Feather、IPC 读写)、arrow/tabular(Table/RecordBatch/Schema)、arrow/c(C Data Interface 往返)等子目录,与matlab/src/matlab/+arrow下的包结构一一对应,因此IncludeSubfolders = true的参数在递归测试中是必需的。

三、编写测试:类基单元测试框架

指南明确要求:所有 MATLAB 接口的测试都应使用 MATLAB 类基单元测试框架,即测试类继承自matlab.unittest.TestCase。官方示例如下——验证通过arrow.array网关函数从 MATLABstring数组构造arrow.array.StringArray,并验证能转换回 MATLABstring数组:

classdef tStringArray < matlab.unittest.TestCase methods(Test) function TestBasicStringArray(testCase) % 验证可以使用 `arrow.array` 网关构造函数 % 从基本的 MATLAB `string` 数组创建 `arrow.array.StringArray`。 % 创建一个基本的 MATLAB `string` 数组。 matlabArray = ["A" ,"B", "C"]; % 使用 `arrow.array` 网关构造函数, % 从 MATLAB `string` 数组创建 `arrow.array.StringArray`。 arrowArray = arrow.array(matlabArray); % 验证 `arrowArray` 的类是 `arrow.array.StringArray`。 testCase.verifyEqual(string(class(arrowArray)), "arrow.array.StringArray"); % 验证 `arrowArray` 可以转换回 MATLAB `string` 数组。 testCase.verifyEqual(arrowArray.toMATLAB, ["A"; "B"; "C"]); end end end

在 matlab/test 目录中可以找到大量真实测试范例。例如 tStringArray.m 展示了项目中沉淀下来的进阶写法:

  • 通过properties声明可复用的测试元数据(ArrowArrayClassNameArrowArrayConstructorFcnMatlabArrayFcnNullSubstitutionValueArrowType),让多个methods(Test)方法共享同一套构造与转换函数句柄;
  • 使用methods(TestClassSetup)编写类级前置检查,例如verifyOnMatlabPath会在每个测试类开始前验证arrow.array.StringArray已在 MATLAB 搜索路径上,并以清晰的错误提示引导用户用addpath修复环境问题:
methods(TestClassSetup) function verifyOnMatlabPath(tc) % Verify the arrow array class is on the MATLAB Search Path. tc.assertTrue(~isempty(which(tc.ArrowArrayClassName)), ... """" + tc.ArrowArrayClassName + """ must be on the MATLAB path. " + ... "Use ""addpath"" to add folders to the MATLAB path."); end end

这种"前置检查 + 元数据驱动"的模式正是指南"测试最佳实践"的落地体现,也为新写测试提供了可直接模仿的模板。

测试最佳实践

指南列出了编写测试时的六条准则:

  • 使用描述性的测试用例名称;
  • 每个测试用例只聚焦测试一个软件"行为";
  • 同时使用"预期"和"非预期"输入进行测试;
  • 在每个测试用例开头添加注释,说明该用例验证什么;
  • 像对待其他代码一样对待测试代码(清晰的变量命名、编写辅助函数、利用抽象等);
  • 向已有测试类添加新用例时,遵循既有模式。

从 tStringArray.m 等测试文件看,"预期与非预期输入并用"具体体现为:除了常规标量/向量输入,还专门覆盖空数组边界(如string.empty(0, 0)0x1空向量),以及含missing值的转换路径(NullSubstitutionValue = string(missing))。

四、测试用例设计准则:真实工作流与 Proxy 层验证

指南在"Test Case Design Guidelines"一节提出两条设计原则:

  1. 覆盖真实工作流:新增测试时,至少应确保真实世界的操作流程按预期工作(例如 MATLAB 数组 → Arrow 数组 → 序列化 → 读回的端到端路径,可参考 matlab/test/arrow/io/feather/tRoundTrip.m 这类 round-trip 测试);
  2. 难以在 MATLAB 接口层测试时,直接测试 C++ Proxy:如果某个改动不容易在 MATLAB 接口层面测试(例如想测试某个 C++Proxy方法的行为),可以考虑在 MATLAB 测试用例中手动创建Proxy实例并调用其相关方法。

指南引用的范例 tTabularInternal.m 正是这一思路的完整示范。该文件针对 Table/RecordBatch 的内部功能(对应 C++ 侧 get_row_as_string.h 实现的getRowAsString方法):

  • 通过properties(TestParameter)+methods(TestParameterDefinition, Static)使用测试参数化机制,一次性构造三种规模的 Tabular 对象(含全部受支持数组类型的表、单列表、三行表),供多个测试方法共享:
methods (TestParameterDefinition, Static) function TabularObjectWithAllTypes = initializeTabularObjectWithAllTypes() arrays = arrow.internal.test.tabular.createAllSupportedArrayTypes(NumRows=1); arrowTable = arrow.tabular.Table.fromArrays(arrays{:}); arrowRecordBatch = arrow.tabular.Table.fromArrays(arrays{:}); TabularObjectWithAllTypes = struct(Table=arrowTable, ... RecordBatch=arrowRecordBatch); end end
  • 测试方法内直接取出Proxy并断言其方法输出,例如验证全部类型行的字符串化结果:
proxy = TabularObjectWithAllTypes.Proxy; expectedString = strjoin(columnStrs, " | "); actualString = proxy.getRowAsString(struct(Index=int64(1))); testCase.verifyEqual(actualString, expectedString);
  • 同时覆盖非预期输入:对非法行索引(0 或超出行数)调用getRowAsString,用testCase.verifyError断言抛出指定错误 ID"arrow:tabular:GetRowAsStringFailed"。这种"按错误 ID 精确断言"的写法值得在新测试中沿用。

五、测试组织:源码与测试的平行结构

所有 MATLAB 接口测试都位于 matlab/test 目录下,并遵循两条组织规则,方便按源码文件快速定位对应测试:

  1. 源码目录与测试目录保持(近似的)平行结构。例如测试目录 matlab/test/arrow/array 中的测试,对应源码目录 matlab/src/matlab/+arrow/+array;
  2. 一个测试文件对应一个源文件。例如 matlab/test/arrow/array/tArray.m 是 matlab/src/matlab/+arrow/+array/Array.m 的测试文件。

对照仓库实际目录结构可以印证这套约定:matlab/src/matlab/+arrow下的包(+array+buffer+tabular+type+io+c等)在matlab/test/arrow下都有同名子目录;测试文件名以t开头(tArray.mtSchema.m)、辅助/夹具类以h开头(如 hNumericArray.m、hTabular.m)。

指南同时说明了一条例外情形:当某个类非常复杂且功能高度分化时(项目一般会尽量避免这种情况),可以把测试拆分为多个"聚焦"的测试文件,例如一个测显示、一个测属性、一个测方法。tTabularInternal.m 这类针对"内部功能"的独立测试文件即属于此类拆分。

六、CI 工作流:matlab.yml 触发与执行

Apache Arrow 项目使用 GitHub Actions 作为主要的持续集成平台。提交一个改动 MATLAB 接口的 pull request 会自动触发 MATLAB CI 工作流,这些工作流会运行matlab/test目录下的全部测试。评审者通常期望 MATLAB CI 工作流成功通过后才考虑合并 PR;如果遇到难以理解的 CI 失败,可以向评审者或社区成员求助。

仓库中的工作流定义位于 .github/workflows/matlab.yml,从该文件可以确认以下执行细节:

  • 触发路径on.push/pull_requestpaths过滤为.github/workflows/matlab.ymlci/scripts/matlab*.shmatlab/**cpp/src/arrow/**——即不仅 MATLAB 代码变更会触发测试,C++ 核心(cpp/src/arrow/**)的变更也会触发 MATLAB 测试,因为接口底层依赖 Arrow C++ 库;
  • 跳过 WIP:每个 job 带有if: ${{ !contains(github.event.pull_request.title, 'WIP') }}条件,标题含 WIP 的 PR 不运行;
  • 平台矩阵:Ubuntu 22.04(AMD64)、macOS(AMD64 与 ARM64 双架构)、Windows 2022 三个 job,均通过matlab-actions/setup-matlab安装MATLAB R2025b(而本地覆盖率功能要求 R2023b 或更高,本地开发版本可据此选择);
  • 构建与测试:先执行ci/scripts/matlab_build.sh $(pwd)构建 MATLAB 接口,再通过matlab-actions/run-tests运行测试,关键参数为select-by-folder: matlab/teststrict: true,并通过环境变量MATLABPATH: matlab/install/arrow_matlab把安装目录加入 MATLAB 搜索路径——这与本地运行测试前需要保证arrow.*类在搜索路径上的要求(见tStringArray.mverifyOnMatlabPath前置检查)完全一致;
  • 构建缓存:Ubuntu/macOS job 使用 ccache 并按cpp/**matlab/**的 hash 作为缓存键,加速 C++ 部分的重建。

此外,仓库还提供了一条独立于测试的打包流水线定义 dev/tasks/matlab/github.yml,在三大平台构建后将产物打包为 MLTX 工具箱(packageMatlabInterface),说明matlab/test的测试通过是接口交付链路的第一道质量门。

七、代码覆盖率目标与检查方法

指南在"Code Coverage Goals"一节提出:

  • 修改 MATLAB 接口时,请尽力为所有变更的行、条件和分支添加测试;
  • 提交 PR 前检查变更代码的覆盖率,并尽可能在 PR 描述中明确说明覆盖率情况;
  • 项目追求高覆盖率,但理解到部分代码无法被合理测试(例如枚举值switch条件中"不可达"的分支)。

生成覆盖率报告(要求 MATLAB R2023b 或更高)

通过给runtests命令传入ReportCoverageFor名称-值对参数即可生成 MATLAB 代码覆盖率报告。生成报告前,记得先把源码目录加入 MATLAB 搜索路径:

>> addpath( genpath(<your local arrow/matlab>) ) % 需要 genpath 来包含所有子目录并加入 MATLAB 搜索路径。 >> runtests(testFilePath/testFolderPath, 'ReportCoverageFor', sourceFilePath/sourceFolderPath, 'IncludeSubfolders', true/false);

指南给出的完整示例:运行matlab/test下所有测试,并获取matlab/src/matlab下所有文件的覆盖率报告(以下路径以 Windows 为例):

>> addpath(genpath("C:\TryCodeCoverage\arrow\matlab")) >> runtests('C:\TryCodeCoverage\arrow\matlab\test', 'ReportCoverageFor', 'C:\TryCodeCoverage\arrow\matlab\src\matlab\', 'IncludeSubfolders', true);

从源码结构看,genpath的作用是把matlab/src/matlab下的+arrow包目录树整体加入搜索路径,使arrow.arrayarrow.tabular.Table等类在测试和覆盖率统计中均可被解析——这也是 matlab/README.md 中 CI 之外手动运行测试时的前提。

实用技巧:调试覆盖率结果

指南"Tips"一节指出:如果runtests命令配合ReportCoverageFor输出了令人困惑或不正确的覆盖率结果,可能是缓存或其他问题导致的。变通办法是:在源文件中设置断点,然后重新运行测试,以验证该源文件确实被测试执行到了。

八、小结

本文以 matlab/doc/testing_guidelines_for_the_matlab_interface_to_apache_arrow.md 为主体,结合仓库源码与 CI 配置,梳理了 Apache Arrow MATLAB 接口测试的完整实践链路:

环节关键做法对应仓库证据
本地运行runtests(file)单文件 /runtests(folder, IncludeSubfolders=true)递归matlab/README.md、matlab/test
测试编写继承matlab.unittest.TestCase,前置检查、参数化、按错误 ID 断言tStringArray.m、tTabularInternal.m
Proxy 层验证在测试中直接获取Proxy并调用 C++ 侧方法tTabularInternal.m、get_row_as_string.h
目录组织测试目录与+arrow包平行、一测试文件对一源文件matlab/test/arrow/array ↔ matlab/src/matlab/+arrow/+array
CIpaths 触发(含cpp/src/arrow/**)、三平台 R2025b、strict: true.github/workflows/matlab.yml
覆盖率ReportCoverageFor参数 +addpath(genpath(...)),要求 R2023b+测试指南"Code Coverage Goals"一节

遵循这套规范,你的每一次 MATLAB 接口改动都能以可复现的方式通过本地测试与 CI 校验,并以足够的覆盖率支撑合并评审。

【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询