C++中的CATCH单元测试与std::array比较

4

我喜欢使用Catch进行我的C++单元测试。我的目标是比较std::arraystd::vector。我创建了这个失败的示例。

#define CATCH_CONFIG_MAIN
#include "catch.hpp"

TEST_CASE("Vector") {
    std::vector<double> direction = {0.1, 0.3, 0.4};
    std::vector<double> false_direction = {0.1, 0.0, 0.4};
    REQUIRE(direction == false_direction);
}

TEST_CASE("Array") {
    std::array<double, 3> direction = {0.1, 0.3, 0.4};
    std::array<double, 3> false_direction = {0.1, 0.0, 0.4};
    REQUIRE(direction == false_direction);
}

这个测试的输出是为了检查std::vector。要求方向等于假方向,扩展如下:{0.1, 0.3, 0.4} == {0.1, 0.0, 0.4}。同时也是为了检查std::array,要求方向等于假方向,扩展如下:{?} == {?}。我该如何显示实际值和期望值?我希望在std::array条件不满足时能够像std::vector一样显示。我使用的是最新版本的catch(v1.10.0)。
3个回答

4
基本上这是一个关于如何将类型转为字符串的问题,对此有文档可以参考。
简略版的算法如下:
  1. 检查对于给定类型是否有 Catch::StringMaker 的特化。如果存在,则使用它。

  2. 检查对于给定类型是否有 operator<< 重载。如果存在,则使用它。

  3. 使用 "{?}"。

最近,Catch 提供了 std::vector 的特化,但没有提供 std::array 的特化,因为 std::array 是 C++11 的一部分且使用较少。自 2.1.0 版本之后,Catch 改为检查类型是否提供容器化接口,即响应 begin(T)end(T)。这提供了许多不同类型的自动字符串化,包括 std::vectorstd::array,以及静态数组。

1

我没有检查Catch的源代码,以了解他们如何实现REQUIRE子句,以及为什么它不起作用,但vector却可以。 但是这里有一个解决方法:

#define COMPARE_ARRAYS(lhs, rhs) compareArrays(Catch::getResultCapture().getCurrentTestName(), __LINE__, lhs, rhs)

template < typename T, size_t N >
void compareArrays(const std::string & test, unsigned line, std::array<T, N> lhs, std::array<T, N> rhs) {
  std::vector<T> lv(lhs.begin(), lhs.end());
  std::vector<T> rv(rhs.begin(), rhs.end());
  INFO("Test case [" << test << "] failed at line " << line); // Reported only if REQUIRE fails
  REQUIRE(lv == rv);
}

TEST_CASE("Array") {
    std::array<double, 3> direction = {0.1, 0.3, 0.4};

    std::array<double, 3> true_direction = {0.1, 0.3, 0.4};
    COMPARE_ARRAYS(direction, true_direction);

    std::array<double, 3> false_direction = {0.1, 0.0, 0.4};
    COMPARE_ARRAYS(direction, false_direction);
}

这肯定能行,但会降低测试代码的可读性。 - schorsch312
@schorsch312,改进后的方案更加清晰、可重用且不会影响测试输出信息。 - Daniel Trugman

1
我追踪了问题并定位到了catch头中的toString方法。它缺少对std::array的重载,而std::vector已经被实例化。我将提交这个更改到catch项目中。
// already exists in the catch header
template<typename T, typename Allocator>
std::string toString( std::vector<T,Allocator> const& v ) {
    return Detail::rangeToString( v.begin(), v.end() );
}

// my modification in the catch header
template<typename T, std::size_t _Nm>
std::string toString( std::array<T, _Nm> const& v ) {
    return Detail::rangeToString( v.begin(), v.end() );
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接