测试 🧪#

在本节中,我们概述了 Arrow 中单元测试所需的步骤。

我们使用 pytest 进行 Python 中的单元测试。有关所需软件包的更多信息,请参阅 Python 单元测试部分

结构

PyArrow 中的测试布局遵循 pytest 的结构,用于 作为应用程序代码一部分的测试

pyarrow/
    __init__.py
    csv.py
    dataset.py
    ...
    tests/
        __init__.py
        test_csv.py
        test_dataset.py
        ...

Parquet 的测试位于单独的文件夹 pyarrow/tests/parquet/ 中。

运行测试

要运行特定的单元测试,请从 arrow/python 文件夹中的终端使用以下命令

$ pytest pyarrow/tests/test_file.py -k test_your_unit_test

运行一个文件中的所有测试

$ pytest pyarrow/tests/test_file.py

运行所有测试

$ pytest pyarrow

您还可以使用 python -m pytest [...] 运行测试,这几乎等同于直接使用 pytest [...],除了通过 python 调用还会将当前目录添加到 sys.path,并且在某些情况下如果 pytest [...] 导致 ImportError 时会有所帮助。

重新编译 PyArrow 或 Arrow C++

如果测试开始失败,请尝试重新编译 PyArrow 或 Arrow C++。请参阅 构建其他 Arrow 库 部分下 PyArrow 选项卡中的说明。

夹具

在 PyArrow 测试文件中,可以定义辅助函数和夹具。还使用了其他 pytest 装饰器,例如 @parametrize@skipif

例如

  • _alltypes_exampletest_pandas 中为所有数据类型提供了一个包含 100 行的数据框。

  • _check_pandas_roundtriptest_pandas 中断言从 Pandas 通过 pa.Tablepa.RecordBatch 返回到 Pandas 的往返是否产生相同的结果。

  • large_buffer 夹具向 test_serialization.py 中的函数 test_primitive_serialization(large_buffer) 提供一个固定大小的 PyArrow 缓冲区。

因此,最好浏览您计划向其中添加测试的文件,并查看是否有任何定义的函数或夹具会有所帮助。

有关 pytest 的更多一般信息,请访问 完整 pytest 文档

我们使用 testthat 进行 R 中的单元测试。更具体地说,我们使用的是 testthat 的第 3 版。在极少数情况下,我们可能需要 testthat 第 2 版的行为,这由 testthat::local_edition(2) 指示。

结构

预期通常的 testthat 文件夹结构

tests
 ├── testthat      # test files live here
 └── testthat.R    # runs tests when R CMD check runs (e.g. with devtools::check())

这是使用 testthat 在 R 中进行测试的基本结构。诸如 testthat.R 之类的文件预计不会经常更改。对于 arrow R 包,testthat.R 还定义了如何在控制台中显示/报告各种测试的结果。

通常,R/ 子文件夹中的大多数文件在 tests/testthat 中都有一个相应的测试文件。

运行测试

要在本地运行包中的所有测试,请调用

devtools::test()

在 R 控制台中。或者,您可以使用

$ make test

在 shell 中。

您可以使用以下命令运行打开的单个测试文件中的测试

devtools::test_active_file()

所有测试也作为我们持续集成 (CI) 管道的一部分运行。

Arrow R 开发人员指南还提供了一个部分,介绍如何运行测试。

良好实践

一般来说,任何对源代码的更改都需要伴随着单元测试。在合并拉取请求之前,所有测试都应通过。

  • 添加功能 -> 添加单元测试

  • 修改功能 -> 更新单元测试

  • 解决错误 -> 在解决错误之前添加单元测试,这有助于证明错误及其修复

  • 性能改进应反映在基准测试中(这同样也是测试)

  • 例外情况可能是重构由单元测试完全涵盖的功能

一个好的经验法则是:如果新功能是面向用户或 API 更改,则几乎肯定需要更改测试——如果不需要更改任何测试,则可能意味着测试不正确!如果新功能是重构并且没有更改任何 API,则可能不需要更改测试。

测试助手

为了补充 testthat 功能,arrow R 包定义了一系列特定的实用程序函数(称为助手),例如

  • 期望 - 这些以 expect_ 开头,用于比较对象

    • 例如,expect_…_roundtrip() 函数接受输入,将其转换为其他格式(例如 arrow、altrep),然后将其转换回,确认值相同。

      x <- c(1, 2, 3, NA_real_)
      expect_altrep_roundtrip(x, min, na.rm = TRUE)
      
  • skip_ - 跳过单元测试 - 将其视为可接受的失败。我们可能希望跳过单元测试的情况

    • skip_if_r_version() - 这是一个特定的 arrow 跳过。例如,当 R 版本为 3.5.0 及以下版本时,我们使用它跳过单元测试(skip_if_r_version(“3.5.0”))。当我们正在测试的功能依赖于 R 3.5.0 之后引入的功能(例如,在 R 3.5.0 中引入的向量的替代表示形式 Altrep,但在后续版本中进行了重大添加)时,您可能会看到它被使用。作为我们的 CI 工作流程的一部分,我们针对不同版本的 R 进行测试,这就是此功能发挥作用的地方。

    • skip_if_not_available() - 另一个特定的 {arrow} 跳过。Arrow (libarrow) 具有许多可以在构建时打开或关闭的可选功能。如果单元测试依赖于此类功能并且此功能不可用(即在构建 libarrow 时未选择),则会跳过测试,而不是出现失败的测试。

    • skip_if_offline() - 不会运行需要互联网连接的测试

    • skip_on_os() - 用于特定于操作系统的单元测试。

    重要:一旦满足 skip_() 语句的条件,同一 test_that() 测试块中的任何其他代码行都不会执行。如果 skip 位于 test_that() 代码块之外,它将跳过文件的其余部分。

有关一般 R 中单元测试的更多信息

  • testthat 网站

  • Hadley Wickham 和 Jenny Bryan 的 R 包 书籍