測試

在本機設定開發環境

請依照我們的安裝說明,並設定適合從原始碼建置 statsmodels 的環境。我們建議您使用 venv 中 statsmodels 的開發安裝版本來進行開發,方法是執行

python -m venv .venv
python -m pip install -e ".[develop]"

從 git 儲存庫的根目錄。旗標 -e 是用於可編輯模式。

此命令會編譯 C 程式碼,並透過建立從您的 Python 環境的程式庫到 statsmodels 原始碼的連結,將 statsmodels 新增至您啟用的 Python 環境。因此,對純 Python 程式碼的變更會立即對使用者可用,無需重新安裝。對 C 程式碼或 Cython 程式碼的變更需要重新執行 python -m pip install -e ".[develop]" 才能使這些變更生效。

測試驅動開發

我們努力遵循測試驅動開發 (TDD) 模式。所有新增至主要程式碼庫的模型或統計函數都必須與現有的統計套件進行測試 (如果可能的話)。

pytest 簡介

如同許多套件,statsmodels 使用 pytest 測試系統,以及 numpy.testing 中的方便擴充功能。Pytest 會找到任何以 testTest 開頭的檔案、目錄、函數或類別名稱 (僅限類別)。測試函數應以 test 開頭,測試類別應以 Test 開頭。這些函數和類別應放置在以 test 開頭的檔案中,並位於名為 tests 的目錄中。

執行測試

測試是透過呼叫 pytest 從命令列執行的。直接使用 pytest 執行測試需要使用 python -m pip install -e ".[develop]" 安裝 statsmodels,如上所述。

測試可以在不同的粒度層級執行

  • 專案層級,會執行所有測試。執行整個測試套件速度很慢,通常只有在對 statsmodels 進行重大變更時才需要這樣做。

pytest statsmodels
  • 資料夾層級,會執行資料夾下的所有測試

pytest statsmodels/regression/tests
  • 檔案層級,會執行檔案中的所有測試

pytest statsmodels/regression/tests/test_regression.py
  • 類別層級,會執行類別中的所有測試

pytest statsmodels/regression/tests/test_regression.py::TestOLS
  • 測試層級,會執行單一測試。第一個範例會執行類別中的測試。第二個範例會執行獨立的測試。

pytest statsmodels/regression/tests/test_regression.py::TestOLS::test_missing
pytest statsmodels/regression/tests/test_regression.py::test_ridge

如何撰寫測試

NumPy 提供了使用 pytest 和 NumPy 擴充功能進行單元測試的良好簡介此處。值得一讀以了解更多詳細資訊。在此,我們將記錄一些我們遵循的慣例,這些慣例值得一提。通常,我們希望一次測試整個模型,而不僅僅是一個函數,例如。以下是精簡版的 test_discrete.py 版本。在此範例中,需要測試幾個具有不同選項的不同模型。測試如下所示

from numpy.testing import assert_almost_equal
import statsmodels.api as sm
from results.results_discrete import Spector

class CheckDiscreteResults(object):
    """
    res2 are the results. res1 are the values from statsmodels
    """

    def test_params(self):
        assert_almost_equal(self.res1.params, self.res2.params, 4)

    decimal_tvalues = 4
    def test_tvalues(self):
        assert_almost_equal(self.res1.params, self.res2.params, self.decimal_tvalues)

    # ... as many more tests as there are common results

class TestProbitNewton(CheckDiscreteResults):
    """
    Tests the Probit model using Newton's method for fitting.
    """

    @classmethod
    def setup_class(cls):
        # set up model
        data = sm.datasets.spector.load()
        data.exog = sm.add_constant(data.exog)
        cls.res1 = sm.Probit(data.endog, data.exog).fit(method='newton', disp=0)

        # set up results
        res2 = Spector.probit
        cls.res2 = res2

        # set up precision
        cls.decimal_tvalues = 3

    def test_model_specifc(self):
        assert_almost_equal(self.res1.foo, self.res2.foo, 4)

主要的執行者是 CheckDiscreteResults 類別。請注意,我們可以在子類別 TestProbitNewton 中設定 tvalues 的精確度,使其與預設值不同。所有測試類別都有一個名為 @classmethodsetup_class。否則,pytest 會在每個測試方法之前重新實例化類別。如果模型的擬合耗時,這顯然是不受歡迎的。最後,我們在底部有一個指令碼,以便我們可以在執行 Python 檔案時執行測試。

測試結果

測試結果是上述範例的最後一部分。對於許多測試,尤其是模型的測試,有許多您希望測試的結果。因此,將硬式編碼的結果與實際測試分開,以使測試更具可讀性是有意義的。如果只有少數結果,則無需分開結果。我們通常從其他統計套件取得結果。請務必記錄您從何處取得結果,以及它們與我們取得的結果可能不同的原因。每個測試資料夾都有一個 results 子目錄。請考慮離散模型的資料夾結構

tests/
    __init__.py
    test_discrete.py
    results/
        __init__.py
        results_discrete.py
        nbinom_resids.csv

如何最好地架構結果取決於您。在離散模型範例中,您會注意到有基於特定資料集的結果類別,以及一個用於載入該資料集的不同模型結果的方法。如果比將結果放在類別本身更容易,您也可以加入文字檔,其中包含要由結果類別載入的結果。

加快完整執行速度

執行完整測試套件速度很慢。幸運的是,只有在進行低階變更時 (例如,變更 statsmodels.base) 才需要執行完整套件。有兩種方法可在需要時加快完整測試套件的執行速度。

  • 使用 pytest-xdist 套件

python -m pip install pytest-xdist
export MKL_NUM_THREADS=1
export OMP_NUM_THREADS=1
pytest -n auto statsmodels
  • 使用 --skip-slow 跳過慢速測試

pytest --skip-slow statsmodels

您可以結合這兩種方法以獲得更快的執行速度。

export MKL_NUM_THREADS=1 && export OMP_NUM_THREADS=1
pytest -n auto --skip-slow statsmodels

test() 方法

statsmodels 的根目錄和所有子模組都公開一個 test() 方法,可用於執行套件中的所有測試 (statsmodels.test()) 或模組中的所有測試 (statsmodels.regression.test())。此方法允許從 statsmodels 的安裝副本執行測試,即使它不是使用如上所述的可編輯旗標安裝的也一樣。此方法是發行版本中測試 wheel 所必需的,且建議用於開發。

使用此方法,所有測試都是使用以下方式執行的

import statsmodels.api as sm
sm.test()

子模組測試是使用以下方式執行的

sm.discrete.test()

test([extra_args, exit])

執行測試套件


上次更新:2024 年 10 月 03 日