测试

在本地设置开发环境

按照我们的 安装说明 并设置一个合适的环境以从源代码构建 statsmodels。我们建议您在 venv 中使用 statsmodels 的开发安装进行开发,方法是运行

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

从 git 存储库的根目录。标志 -e 用于可编辑。

此命令编译 C 代码并将 statsmodels 添加到您的激活 Python 环境中,方法是创建从您的 Python 环境库到 statsmodels 源代码的链接。因此,对纯 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 类。请注意,我们可以将 tvalues 的精度级别设置为不同于子类 TestProbitNewton 中的默认值。所有测试类都有一个名为 @classmethod 的方法,名为 setup_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

The test() 方法

statsmodels 的根目录和所有子模块都公开了一个 test() 方法,可用于运行软件包中的所有测试 (statsmodels.test()) 或模块中的所有测试 (statsmodels.regression.test())。此方法允许从 statsmodels 的安装副本运行测试,即使它不是使用如上所述的可编辑标志安装的。此方法是为在发布版本中测试轮子而必需的,建议在开发中使用。

使用此方法,所有测试都使用以下方法运行

import statsmodels.api as sm
sm.test()

子模块测试使用以下方法运行

sm.discrete.test()

test([extra_args, exit])

运行测试套件


上次更新:2024 年 10 月 3 日