測試 🧪#

在本節中,我們概述在 Arrow 中進行單元測試所需的步驟。

我們在 Python 中使用 pytest 進行單元測試。有關所需套件的更多資訊,請參閱 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 標籤下的註解。

夾具 (Fixtures)

在 PyArrow 測試檔案中,可以定義輔助函數和夾具 (fixtures)。也使用了其他 pytest 裝飾器,例如 @parametrize@skipif

例如

  • _alltypes_exampletest_pandas 中為所有資料類型提供一個包含 100 列的資料框架。

  • _check_pandas_roundtriptest_pandas 中斷言從 Pandas 經過 pa.Tablepa.RecordBatch 再回到 Pandas 的往返是否產生相同的結果。

  • large_buffer 夾具 (fixture) 為 test_serialization.py 中的函數 test_primitive_serialization(large_buffer) 提供固定大小的 PyArrow 緩衝區。

因此,最好瀏覽您計劃新增測試的檔案,看看是否有任何已定義的函數或夾具 (fixtures) 會有所幫助。

有關 pytest 的更多資訊,請訪問 完整 pytest 文件

我們在 R 中使用 testthat 進行單元測試。更具體地說,我們使用 testthat 的第三版。在極少數情況下,我們可能需要 testthat 第二版的行為,這由 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 開發人員指南也有一個章節 介紹如何執行測試。

良好實務

一般來說,對原始碼的任何變更都需要附帶單元測試。所有測試都應在 Pull Request 合併之前通過。

  • 新增功能 -> 新增單元測試

  • 修改功能 -> 更新單元測試

  • 解決錯誤 -> 在解決錯誤之前新增單元測試,這有助於證明錯誤及其修復

  • 效能改進應反映在效能基準 (benchmark) 中 (這也是測試)

  • 例外情況可能是重構完全由單元測試涵蓋的功能

一個好的經驗法則是:如果新功能是面向使用者或 API 的變更,您幾乎肯定需要變更測試 — 如果不需要變更測試,則可能表示測試不正確!如果新功能是重構且沒有 API 變更,則可能不需要變更測試。

測試輔助函數

為了補充 testthat 功能,arrow R 套件定義了一系列特定的實用函數 (稱為輔助函數),例如

  • 期望 (expectations) - 這些以 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 版本之後引入的功能時 (例如向量的替代表示法 Altrep,在 R 3.5.0 中引入,但在後續版本中進行了重大新增),您可能會看到它被使用。作為我們 CI 工作流程的一部分,我們會針對不同版本的 R 進行測試,而這就是此功能的作用所在。

    • skip_if_not_available() - 另一個特定的 {arrow} 跳過。Arrow (libarrow) 有許多可開啟或關閉的可選功能 (這在建置時發生)。如果單元測試依賴於此類功能,並且此功能不可用 (即在建置 libarrow 時未選擇),則會跳過測試,而不是測試失敗。

    • skip_if_offline() - 將不會執行需要網際網路連線的測試

    • skip_on_os() - 用於特定於 OS 的單元測試。

    重要:一旦滿足 skip_() 語句的條件,同一個 test_that() 測試區塊中的其他程式碼行將不會被執行。如果 skiptest_that() 程式碼區塊之外,它將跳過檔案的其餘部分。

有關 R 中單元測試的更多一般資訊

  • testthat 網站

  • Hadley Wickham 和 Jenny Bryan 的 R Packages 書籍