我正在使用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::equal
或std::mismatch
,但这也需要很多样板。
有更简洁的方法吗?
答案 0 :(得分:31)
使用BOOST_CHECK_EQUAL_COLLECTIONS
。它是test_tools.hpp
中的一个宏,需要两对迭代器:
BOOST_CHECK_EQUAL_COLLECTIONS(values.begin(), values.end(),
expected.begin(), expected.end());
它将报告索引和不匹配的值。如果大小不匹配,它也会报告(并且不会仅仅从向量的末尾开始)。
请注意,如果您要将BOOST_CHECK_EQUAL
或BOOST_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。
答案 1 :(得分:12)
有点偏离主题,但是,有时需要使用comparison with tolerance来比较浮点数的集合,那么这个代码段可能是有用的:
// 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);
答案 2 :(得分: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):“test”中的错误:检查{col1,col1 + 7} == {col2,col2 + 7}失败。
位置2:3不匹配!= 4
位置5:6不匹配!= 7
在测试套件“example”中检测到* 1失败
答案 3 :(得分:5)
您可以将BOOST_REQUIRE_EQUAL_COLLECTIONS
与std::vector<T>
一起使用,但是当您拥有矢量矢量或值为矢量的地图时,您必须教授Boost.Test如何打印std::vector
。当你有地图时,需要教会如何打印Boost.Test std::pair
。由于您无法更改std::vector
或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
将告诉您不匹配项的索引以及两个集合的内容。如果它们具有不同的尺寸,那么这被认为是不匹配的并且印刷了不同的尺寸。
答案 4 :(得分:5)
自Boost 1.59起,比较std::vector
实例要容易得多。请参阅this documentation版本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() );