添加和运行测试

高质量的测试套件对于确保代码库的正确性和健壮性至关重要。在这里,我们提供如何运行单元测试以及如何添加新测试的说明。

目录

添加新的单元测试

Python 包:pytest

将您的测试添加到以下目录中

请参考PyTest 教程,学习如何为 Python 代码编写测试。

您可以按照本节中的说明尝试运行您的测试。

C++:Google Test

将您的测试添加到目录tests/cpp/下。请参考这个关于使用 Google Test 的优秀教程

您可以按照本节中的说明尝试运行您的测试。注意:需要 Google Test 版本 1.8.1 或更高。

JVM 包:JUnit / scalatest

XGBoost 的 JVM 包(XGBoost4J / XGBoost4J-Spark)使用Maven 标准目录布局。具体来说,JVM 包的测试位于以下位置

要编写 Java 代码的测试,请参阅JUnit 5 教程。要编写 Scala 代码的测试,请参阅Scalatest 教程

您可以按照本节中的说明尝试运行您的测试。

R 包:testthat

将您的测试添加到目录R-package/tests/testthat下。请参考这个关于 testthat 的优秀教程

您可以按照本节中的说明尝试运行您的测试。

本地运行单元测试

R 包

运行

python ./ops/script/test_r_package.py --task=check

在项目根目录下。该命令会构建并检查 XGBoost r-package。或者,如果您只想运行测试,可以在安装 XGBoost 后使用以下命令

cd R-package/tests/
Rscript testthat.R

JVM 包

使用 Maven

mvn test

Python 包:pytest

要运行 Python 单元测试,首先安装pytest

pip3 install pytest

然后按照构建共享库中的说明编译 XGBoost。最后,在项目根目录调用 pytest

# Tell Python where to find XGBoost module
export PYTHONPATH=./python-package
pytest -v -s --fulltrace tests/python

此外,要测试 CUDA 代码,运行

# Tell Python where to find XGBoost module
export PYTHONPATH=./python-package
pytest -v -s --fulltrace tests/python-gpu

(对于此步骤,您应该已编译启用 CUDA 的 XGBoost。)

要使用分布式框架(如 DaskPySpark)进行测试

# Tell Python where to find XGBoost module
export PYTHONPATH=./python-package
pytest -v -s --fulltrace tests/test_distributed

C++:Google Test

要构建和运行 C++ 单元测试,请在运行 CMake 时启用测试

cmake -B build -S . -GNinja -DGOOGLE_TEST=ON -DUSE_DMLC_GTEST=ON -DUSE_CUDA=ON -DUSE_NCCL=ON
cmake --build build
cd ./build
./testxgboost

诸如 USE_CUDA, USE_DMLC_GTEST 之类的标志是可选的。有关如何从源代码构建 XGBoost 的更多信息,请参阅从源代码构建。也可以使用 ctest 工具运行所有单元测试,该工具提供更高的灵活性。例如

ctest --verbose

如果您需要在 Windows 上使用 VS 调试器调试错误,可以在 test_main.cc 中附加 gtest 标志

::testing::GTEST_FLAG(filter) = "Suite.Test";
::testing::GTEST_FLAG(repeat) = 10;

Sanitizers:检测内存错误和数据竞争

默认情况下,sanitizers 已捆绑在 GCC 和 Clang/LLVM 中。可以使用 GCC >= 4.8 或 LLVM >= 3.1 启用 sanitizers,但某些发行版可能会单独打包 sanitizers。以下是支持的 sanitizers 及其相应的库名称列表

  • Address sanitizer: libasan

  • Undefined sanitizer: libubsan

  • Leak sanitizer: liblsan

  • Thread sanitizer: libtsan

Memory sanitizer 是 LLVM 独有的,因此 XGBoost 不支持。使用像 gcc-9 这样的最新编译器时,指定 sanitizer 标志后,编译器驱动程序应该能够自动链接运行时库。

如何使用 sanitizers 构建 XGBoost

通过指定 -DUSE_SANITIZER=ON,可以构建支持 sanitizer 的 XGBoost。默认情况下,当您打开 USE_SANITIZER 标志时,会使用 address sanitizer 和 leak sanitizer。您始终可以通过向 ENABLED_SANITIZERS 提供以分号分隔的 sanitizer 列表来更改默认设置。请注意,thread sanitizer 与其他两个 sanitizer 不兼容。

cmake -DUSE_SANITIZER=ON -DENABLED_SANITIZERS="address;undefined" /path/to/xgboost

默认情况下,CMake 会在常规系统路径中搜索 sanitizers,您也可以提供指定的 SANITIZER_PATH。

cmake -DUSE_SANITIZER=ON -DENABLED_SANITIZERS="address;undefined" \
-DSANITIZER_PATH=/path/to/sanitizers /path/to/xgboost

如何将 sanitizers 与 CUDA 支持一起使用

在 CUDA 上使用 address sanitizer (asan) 运行 XGBoost 会引发内存错误。要正确地将 asan 与 CUDA 一起使用,您需要通过 ASAN_OPTIONS 环境变量配置 asan

ASAN_OPTIONS=protect_shadow_gap=0 ${BUILD_DIR}/testxgboost

其他 sanitizer 运行时选项

默认情况下,undefined sanitizer 不会打印出回溯。您可以通过导出环境变量来启用它

UBSAN_OPTIONS=print_stacktrace=1 ${BUILD_DIR}/testxgboost

详细信息请参考sanitizers 的官方文档