28

我正在使用 Boost Test 对一些 C++ 代码进行单元测试。

我有一个值向量需要与预期结果进行比较,但我不想手动检查循环中的值:

BOOST_REQUIRE_EQUAL(values.size(), expected.size());

for( int i = 0; i < size; ++i )
{
    BOOST_CHECK_EQUAL(values[i], expected[i]);
}

主要问题是循环检查不打印索引,因此需要进行一些搜索才能找到不匹配的内容。

我可以在这两个向量上使用std::equalor std::mismatch,但这也需要大量的样板文件。

有没有更清洁的方法来做到这一点?

4

5 回答 5

36

使用BOOST_CHECK_EQUAL_COLLECTIONS. 这是一个宏,test_tools.hpp它需要两对迭代器:

BOOST_CHECK_EQUAL_COLLECTIONS(values.begin(), values.end(), 
                              expected.begin(), expected.end());

它将报告不匹配的索引和值。如果大小不匹配,它也会报告(并且不会只是跑出向量的末尾)。


请注意,如果要使用BOOST_CHECK_EQUALBOOST_CHECK_EQUAL_COLLECTIONS使用非 POD 类型,则需要实现

bool YourType::operator!=(const YourType &rhs)  //  or OtherType
std::ostream &operator<<(std::ostream &os, const YourType &yt)

分别用于比较和记录。
传递给的迭代器的顺序BOOST_CHECK_EQUAL_COLLECTIONS决定了比较的 RHS 和 LHS !=- 第一个迭代器范围将是比较中的 LHS。

于 2010-10-22T18:08:48.140 回答
17

然而,有点离题了,当有时需要使用容差比较来比较浮点数的集合时,这个片段可能很有用:

// Have to make it a macro so that it reports exact line numbers when checks fail.
#define CHECK_CLOSE_COLLECTION(aa, bb, tolerance) { \
    using std::distance; \
    using std::begin; \
    using std::end; \
    auto a = begin(aa), ae = end(aa); \
    auto b = begin(bb); \
    BOOST_REQUIRE_EQUAL(distance(a, ae), distance(b, end(bb))); \
    for(; a != ae; ++a, ++b) { \
        BOOST_CHECK_CLOSE(*a, *b, tolerance); \
    } \
}

这不会打印不匹配元素的数组索引,但它会以高精度打印不匹配的值,因此它们通常很容易找到。

示例用法:

auto mctr = pad.mctr();
std::cout << "mctr: " << io::as_array(mctr) << '\n';
auto expected_mctr{122.78731602430344,-13.562000155448914};
CHECK_CLOSE_COLLECTION(mctr, expected_mctr, 0.001);
于 2013-07-06T13:27:17.160 回答
14

std::vector从 Boost 1.59 开始,比较实例要容易得多。请参阅版本 1.63 的此文档(在这方面与 1.59 几乎相同)。

例如,如果你已经声明std::vector<int> a, b;你可以写

BOOST_TEST(a == b);

得到一个非常基本的比较。这样做的缺点是,在失败的情况下,Boost 只会告诉你,a并且b不一样。但是您可以通过比较元素来获得更多信息,这可以以一种优雅的方式进行

BOOST_TEST(a == b, boost::test_tools::per_element() );

或者,如果您想要字典比较,您可以这样做

BOOST_TEST(a <= b, boost::test_tools::lexicographic() );
于 2017-03-29T11:22:57.130 回答
10

BOOST_CHECK_EQUAL_COLLECTIONS怎么样?

BOOST_AUTO_TEST_CASE( test )
{
    int col1 [] = { 1, 2, 3, 4, 5, 6, 7 };
    int col2 [] = { 1, 2, 4, 4, 5, 7, 7 };

    BOOST_CHECK_EQUAL_COLLECTIONS( col1, col1+7, col2, col2+7 );
}

例子

运行 1 个测试用例...

test.cpp(11):“测试”中的错误:检查 { col1, col1+7 } == { col2, col2+7 } 失败。

位置 2 不匹配:3 != 4

位置 5 不匹配:6 != 7

*在测试套件“示例”中检测到 1 个故障

于 2010-10-22T18:10:13.117 回答
5

你可以使用BOOST_REQUIRE_EQUAL_COLLECTIONSwith ,但你必须教 Boost.Test当你有一个向量的向量或一个值为向量的映射时std::vector<T>如何打印 a 。std::vector当您有地图时,需要教 Boost.Test 如何打印std::pair. 由于您无法更改std::vectoror的定义std::pair,因此您必须以这样一种方式执行此操作,即您定义的流插入运算符将由 Boost.Test 使用,而不是std::vector. 此外,如果您不想为了让 Boost.Test 满意而将流插入操作符添加到您的系统中,此技术也很有用。

这是任何的食谱std::vector

namespace boost
{

// teach Boost.Test how to print std::vector
template <typename T>
inline wrap_stringstream&
operator<<(wrap_stringstream& wrapped, std::vector<T> const& item)
{
    wrapped << '[';
    bool first = true;
    for (auto const& element : item) {
        wrapped << (!first ? "," : "") << element;
        first = false;
    }
    return wrapped << ']';
}

}

这会将向量格式化为[e1,e2,e3,...,eN]带有N元素的向量,并且适用于任意数量的嵌套向量,例如,向量的元素也是向量。

这是类似的配方std::pair

namespace boost
{

// teach Boost.Test how to print std::pair
template <typename K, typename V>
inline wrap_stringstream&
operator<<(wrap_stringstream& wrapped, std::pair<const K, V> const& item)
{
    return wrapped << '<' << item.first << ',' << item.second << '>';
}

}

BOOST_REQUIRE_EQUAL_COLLECTIONS会告诉你不匹配项的索引,以及两个集合的内容,假设两个集合大小相同。如果它们的尺寸不同,则视为不匹配,并打印不同的尺寸。

于 2014-08-08T19:45:03.270 回答