正在加载...
正在搜索...
无匹配项
在 libcuspatial 中进行单元测试

libcuspatial 中的单元测试使用 Google Test 编写。

最佳实践:我们应该测试什么?

一般来说,我们应该测试以确保所有代码路径都被覆盖。这并非总是容易或可能的。但通常这意味着我们测试算法和数据类型的所有支持组合,以及算法支持的主要迭代器和容器类型。这里有一些其他指导方针。

  • 测试公共 API。尽量确保公共 API 测试能够覆盖 libcuspatial 代码的 100%(包括内部细节和实用工具)。
  • 测试异常情况。例如,任何导致函数抛出异常 (throw) 的情况。
  • 测试边界情况。例如,恰好落在直线或边界上的点。
  • 通常来说,在 libcuspatial 中,空输入不是错误。通常空输入会导致空输出。测试应该验证这一点。
  • 大多数算法应该有一个或多个测试,使用足够大的行数输入来需要启动多个线程块,特别是在值最终需要在块之间通信时(例如,归约)。这对于自定义内核尤其重要,但也适用于使用 lambda / functor 的 Thrust 和 CUB 算法调用。

仅头文件和基于列的 API 测试

libcuspatial 目前有两种 C++ API:基于列的 API 使用 libcudf 数据结构作为输入和输出。这些测试可以使用 libcudf 的特性来构建列和表。仅头文件 API 完全不依赖于 libcudf,因此这些 API 的测试不应该包含任何 libcudf 头文件。仅头文件和基于列的 API 测试位于 cuspatial/tests 中,但仅头文件 API 测试是 .cu 文件,而基于列的 API 测试是 .cpp 文件。

一般来说,我们在仅头文件 API 的单元测试中测试算法和业务逻辑。基于列的 API 测试应该只涵盖基于列的 API 的具体内容,例如类型处理、输入验证以及仅由该 API 抛出的异常。基于列的 API 测试通常也测试空输入,以确保空列输入导致空列输出,而不是抛出异常。

目录和文件命名

单元测试目录和源文件的命名应与被测试的功能保持一致。例如,针对 distance.hpp 中的 API 的测试文件应位于 cuspatial/cpp/tests/distance/ 目录下。

为了提高编译时间,测试源文件应尽可能使用 .cpp 文件,因为 nvcc 在编译主机代码时比 gcc 慢。请注意,thrust::device_vector 包含设备代码,因此只能在 .cu 文件中使用。rmm::device_uvectorrmm::device_buffer 以及稍后描述的各种 column_wrapper 类型可以在 .cpp 文件中使用,因此在测试代码中优先于 thrust::device_vector 使用。

测试仅头文件 API 需要 CUDA 编译,因此应在 .cu 文件中完成。

基础测试夹具

所有 libcuspatial 单元测试都应该使用 GTest 的 “测试夹具”(Test Fixture)。即使夹具是空的,它也应该继承自位于 cpp/tests/base_fixture.hpp 中的基础夹具 cuspatial::test::BaseFixture。这确保了 RMM 的正确初始化和终结。cuspatial::test::BaseFixture 已经继承自 testing::Test,因此您的测试夹具无需再继承自它。

示例

class MyTestFixture : public cuspatial::test::BaseFixture {...};

类型化测试

通常来说,libcuspatial 的功能必须支持所有受支持的类型(对于 cuspatial 而言,这通常仅指 floatdouble)。为了自动化在多种类型上运行相同测试的过程,我们使用 GTest 的 类型化测试 (Typed Tests)。类型化测试允许您编写一次测试并在类型列表中运行它。

例如

// 夹具必须是模板
template <typename T>
class TypedTestFixture : cuspatial::test::BaseFixture {...};
using TestTypes = ::test::types<float,double>; // 注意自定义的 cudf 类型列表类型
TYPED_TEST_SUITE(TypedTestFixture, TestTypes);
TYPED_TEST(TypedTestFixture, FirstTest){
// 使用 `TypeParam` 访问当前类型
using T = TypeParam;
}
libcuspatial 测试的基础测试夹具类,支持无参数化或仅类型参数化...

在此示例中,所有使用 TypedTestFixture 夹具的测试将对在 TestTypes 中定义的列表(float, double)中的每种类型运行一次。

实用工具

libcuspatial 测试实用工具包括位于 cpp/tests/utility/vector_equality() 中的 cuspatial::test::expect_vector_equivalent()。此函数使用 Google Test 的浮点值近似匹配来比较两个容器。它可以处理 cuspatial::vec_2d<T> 的向量,其中 Tfloatdouble。它在比较之前自动将设备容器中的数据复制到主机容器,因此您可以传入一个主机向量和一个设备向量,例如。

示例

auto h_expected = std::vector<cuspatial::vec_2d<float>>{...}; // 预期值
auto d_actual = rmm::device_vector<cuspatial::vec_2d<float>>{...}; // 实际计算值
cuspatial::test::expect_vector_equivalent(h_expected, d_actual);

在创建自己的测试实用工具之前,查看是否已存在能够满足您需求的工具。如果没有,考虑添加一个新的工具来满足您的需求。然而,请确保该工具足够通用,对其他测试也适用,并且不过分局限于您特定的测试需求。