贡献者指南

测试

师成师成· 更新于 2026-09-28· 阅读 26 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

测试

测试对于确保 DataFusion 正常运行、避免在重构过程中被意外破坏至关重要。所有新功能都应具备测试覆盖,完整的测试套件会作为 CI 的一部分运行。

测试快速上手

在开发某个功能或修复某个缺陷时,最佳实践是先运行最小的、足以让你对自己的改动有信心的测试集合,然后再按需扩大范围。

首先,运行你所修改的 crate 中的测试。例如,如果你修改了 datafusion-optimizer/src 中的文件,就运行对应 crate 的测试:

cargo test -p datafusion-optimizer

然后,运行 sqllogictest 测试套件,它在开发过程中提供了良好的速度与覆盖率的平衡:运行速度快,同时能对 DataFusion 中的大部分 SQL 行为提供广泛的回归覆盖。

cargo test --profile=ci --test sqllogictests

最后,在提交 PR 之前,请运行 datafusion 和 datafusion-cli 核心 crate 的测试:

cargo test -p datafusion
cargo test -p datafusion-cli

某些集成测试需要可选的外部服务(例如由 Docker 支撑的容器),在服务不可用时可能会跳过执行。

测试概览

DataFusion 的测试金字塔包含多个层级的测试,并尽量遵循《Rust 程序设计语言》中描述的 Rust 标准测试组织方式。

使用 cargo 运行测试:

cargo test

你也可以使用其他运行器,例如 cargo-nextest。

cargo nextest run

单元测试

针对单个模块中代码的测试,按照 Rust 的惯例,定义在同一源文件的 test 模块中。

例如,要运行 datafusion crate 中的测试:

cargo test -p datafusion

test_util 模块提供了一些有用的宏,用于高效地编写单元测试,例如针对 RecordBatches 的 assert_batches_sorted_eq 和 assert_batches_eq,以及在整个代码库中被广泛使用的 assert_contains / assert_not_contains。

sqllogictests 测试

DataFusion 的 SQL 实现是使用 sqllogictest 进行测试的。你可以使用如下命令运行这些测试:

# Run all tests
cargo test --profile=ci --test sqllogictests
# Run a specific test file
cargo test --profile=ci --test sqllogictests -- aggregate.slt
# Run a specific test file and update expected outputs
cargo test --profile=ci --test sqllogictests -- aggregate.slt --complete
# Run and update expected outputs for all test files
cargo test --profile=ci --test sqllogictests -- --complete

sqllogictests 对于习惯编写 .rs 测试的新贡献者来说可能没那么方便,因为需要学习另一个工具。然而,基于 sqllogictest 的测试在开发和维护上要容易得多,因为它们 1) 不需要缓慢的重新编译/链接循环,2) 可以自动更新。

与 DuckDB 等类似系统一样,DataFusion 选择用稍高的参与门槛来换取长期的可维护性。

DataFusion 在合并队列中运行 SQLite 的测试套件,然后才会将 PR 合并到 main 分支。有关本地运行的说明,请参阅运行测试:sqlite。

快照测试(cargo insta)

Insta 被用于快照测试。每次运行测试时都会生成快照并进行比较。如果输出发生变化,测试将会失败。

要查看这些变更,可以使用 Insta 命令行工具:

cargo install cargo-insta
cargo insta review

扩展测试

DataFusion 拥有扩展测试(定义于 extended.yml),其运行耗时远超标准测试套件。这些测试提供额外的正确性覆盖,并且必须在合并队列中通过,PR 才能合入 main 分支。

为了节省 CI 资源,这些测试不会在普通的 PR 更新时运行。它们也会在推送至发布分支(branch-*)时运行。你也可以手动运行它们。

有关本地 SQLite 的测试说明,请参阅文档中的说明。

Rust 集成测试

在 tests 目录中,有若干针对 DataFusion 库的公共接口测试。

你可以像使用普通命令那样,通过 cargo 单独运行这些测试,例如:

cargo test -p datafusion --test parquet_integration

SQL “模糊”测试

DataFusion 使用 SQLancer 进行"模糊"测试:它生成随机 SQL 查询并在 DataFusion 上执行,以发现缺陷。

相关代码位于 datafusion-sqllancer 仓库,欢迎进一步贡献。感谢 @2010YOUY01 的最初实现。

文档示例

我们使用 Rust 的 doctest 来验证文档中的示例正确且不过时。这些测试会作为 CI 的一部分运行,你也可以在本地使用以下命令运行它们:

cargo test --doc

API 文档示例

与其他 Rust 项目一样,.rs 文件中文档注释里的示例会被自动检查,以确保它们能够正常运行,并随代码一起演进。

用户指南文档

用户指南中的 Rust 示例代码(任何标记为 ```rust 的内容)也会通过 doc_comment crate 以相同的方式进行测试。更多详情请参阅 core/src/lib.rs 的末尾。

文档链接检查

./dev/rust_lint.sh 会运行内部 Markdown 链接检查。如果缺少 lychee,该脚本会安装 ci/scripts/utils/tool_versions.sh 中固定(pin)的版本。如果已经安装过,脚本会直接使用现有安装,即使其版本与固定版本不同。

单独运行该检查:

source ci/scripts/utils/tool_versions.sh
cargo install lychee --locked --version "${LYCHEE_VERSION}"
bash ci/scripts/markdown_link_check.sh

注意事项:

  • 该脚本使用 bash 运行,并兼容 macOS 上的默认 Bash(不依赖 mapfile)。
  • CI 配置目前只检查内部 Markdown 链接。外部 http(s) 和 mailto 链接会被排除,以避免不稳定的失败。
  • 该检查只报告失效的链接。./dev/rust_lint.sh --write 不会修改它们。

当链接失效时,lychee 会打印出出错的文件以及 URL/路径。例如:

[docs/source/user-guide/cli/overview.md]:
  [ERROR] file:///.../docs/source/user-guide/cli/missing-page.md | Cannot find file: File not found. Check if file exists and path is correct

Rust 文档注释会在 CI 中由 rustdoc 校验,也可以在本地通过以下命令检查:

bash ci/scripts/rust_docs.sh

ASF 状态检查验证

ci/scripts/check_asf_yaml_status_checks.py 会检查 .asf.yaml 中每个必需的状态检查是否与 .github/workflows 中的某个任务相对应,并检查 rust.yml 在推送到 main 时是否只跳过其列出的任务。./dev/rust_lint.sh 会运行该脚本,需要 python3 和 PyYAML。uv 工作区同时提供了这两者:

uv run ./dev/rust_lint.sh

单独运行该检查:

uv run python3 ci/scripts/check_asf_yaml_status_checks.py

安全审计

ci/scripts/security_audit.sh 会针对根目录的 Cargo.lock 运行 cargo audit,并使用 CI 所采用的漏洞例外配置。./dev/rust_lint.sh 也会运行它,并在缺失时安装 cargo-audit。若要单独运行该审计:

./ci/scripts/security_audit.sh

该审计会拉取 RustSec 安全公告数据库。新增一条公告,或者 cargo-audit 版本不同,都可能在仓库没有任何改动的情况下导致结果变化。

大文件检查

ci/scripts/check_large_files.sh 会在基础引用(base ref)到目标引用(head ref)之间提交的任何文件超过 1.5 MB 时失败,这与 "Large files PR check" 工作流在拉取请求上执行的检查相同。./dev/rust_lint.sh 会针对指向 apache/datafusion 的远程上 HEAD 与 main 的合并基准运行该脚本;如果不存在这样的远程,则使用 origin。若要单独运行该检查,或针对不同的范围运行:

./ci/scripts/check_large_files.sh
./ci/scripts/check_large_files.sh --base upstream/main --head my-branch

仅会检查已提交的文件。请先提交更改,再运行该脚本。

依赖检查

CI 会运行两项依赖检查,而 ./dev/rust_lint.sh 会同时运行这两项:

  • ci/scripts/check_circular_dependencies.sh 会构建并运行 dev/depcheck,若 DataFusion 各 crate 之间存在循环依赖则判定失败。
  • ci/scripts/check_unused_dependencies.sh 会在仓库根目录运行 cargo machete --with-metadata。如果缺少 cargo-machete,该检查套件会安装 ci/scripts/utils/tool_versions.sh 中指定的版本。

若要单独运行其中任意一项检查:

./ci/scripts/check_circular_dependencies.sh
./ci/scripts/check_unused_dependencies.sh

Examples README 检查

datafusion-examples/README.md 是由 datafusion-examples/examples/<group>/main.rs 中的文档注释生成的。ci/scripts/check_examples_docs.sh 会重新生成该文件,如果已提交的文件与生成结果不同,脚本将失败。./dev/rust_lint.sh 会运行该脚本,并且需要 cargo 和 npx。若要单独运行此检查,或更新 README:

./ci/scripts/check_examples_docs.sh
./ci/scripts/check_examples_docs.sh --write

配置与函数文档检查

configs.md、aggregate_functions.md、scalar_functions.md 和 window_functions.md 是由 dev/update_config_docs.sh 和 dev/update_function_docs.sh 生成的。要检查它们是否为最新版本,请运行 ci/scripts/check_generated_docs.sh 脚本,该脚本也是 ./dev/rust_lint.sh 执行流程的一部分。使用 --write 参数运行它可以更新这些页面。

基准测试

Criterion 基准测试

Criterion 是一个由统计数据驱动的微基准测试框架,DataFusion 用它来评估特定代码路径的性能。其中,criterion 基准测试既有助于指导优化工作,也能防止 DataFusion 出现性能回退。

Criterion 与 Cargo 内置的基准测试支持集成,可以

cargo bench --bench BENCHMARK_NAME

完整基准测试列表见此处。

cargo-criterion 也可用于生成更高级的报告。

Parquet SQL 基准测试

Parquet SQL 基准测试可通过以下方式运行:

 cargo bench --bench parquet_query_sql

这些测试会随机生成一个 parquet 文件,然后针对该文件运行来自 parquet_query_sql.sql 的查询进行基准测试。因此,这是一种为特定查询路径和/或数据路径快速添加测试覆盖的方式。

如果设置了环境变量 PARQUET_FILE,基准测试将针对该文件运行查询,而不是使用随机生成的文件。这在需要针对同一份源数据进行多次运行(可能使用不同的代码),或者针对自定义数据集进行测试时非常有用。

基准测试会在退出时自动删除生成的 parquet 文件,但如果被中断(例如按下 CTRL+C),则不会删除。这样便于事后分析该特定文件,或将其保留下来在后续运行中配合 PARQUET_FILE 使用。

比较基线

默认情况下,Criterion.rs 会将测量结果与上一次运行(如果有)进行比较。有时,保留一组测量结果以供多次运行使用会很有帮助。例如,你可能希望在多次修改代码的同时与 master 分支进行比较。针对这种情况,Criterion.rs 支持自定义基线。

 git checkout main
 cargo bench --bench sql_planner -- --save-baseline main
 git checkout YOUR_BRANCH
 cargo bench --bench sql_planner --  --baseline main

注意:在 macOS 上,运行 cargo bench 可能需要使用 sudo。

sudo cargo bench ...

有关 基准线(Baselines)的更多信息

上游基准测试套件

关于如何针对 DataFusion 运行上游基准测试套件的说明和工具,可以在 benchmarks 目录中找到。

这些资源对于与其他 Arrow 实现和查询引擎进行对比评估非常有价值。

评论

登录后参与评论

正在加载评论…