libcuspatial 中的单元测试使用 Google Test 编写。
一般来说,我们应该测试以确保所有代码路径都被覆盖。这并非总是容易或可能的。但通常这意味着我们测试算法和数据类型的所有支持组合,以及算法支持的主要迭代器和容器类型。这里有一些其他指导方针。
throw
) 的情况。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_uvector
、rmm::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 而言,这通常仅指 float
和 double
)。为了自动化在多种类型上运行相同测试的过程,我们使用 GTest 的 类型化测试 (Typed Tests)。类型化测试允许您编写一次测试并在类型列表中运行它。
例如
在此示例中,所有使用 TypedTestFixture
夹具的测试将对在 TestTypes
中定义的列表(float, double
)中的每种类型运行一次。
libcuspatial 测试实用工具包括位于 cpp/tests/utility/vector_equality()
中的 cuspatial::test::expect_vector_equivalent()
。此函数使用 Google Test 的浮点值近似匹配来比较两个容器。它可以处理 cuspatial::vec_2d<T>
的向量,其中 T
是 float
或 double
。它在比较之前自动将设备容器中的数据复制到主机容器,因此您可以传入一个主机向量和一个设备向量,例如。
示例
在创建自己的测试实用工具之前,查看是否已存在能够满足您需求的工具。如果没有,考虑添加一个新的工具来满足您的需求。然而,请确保该工具足够通用,对其他测试也适用,并且不过分局限于您特定的测试需求。