Как сравнить векторы с Boost.Test?
Я использую Boost Test для unit test некоторого кода на С++.
У меня есть вектор значений, которые мне нужно сравнить с ожидаемыми результатами, но я не хочу вручную проверять значения в цикле:
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
для двух векторов, но для этого потребуется много шаблонов.
Есть ли более чистый способ сделать это?
Ответы
Ответ 1
Используйте 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 в сравнении.
Ответ 2
Как насчет 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 обнаружен отказ в наборе тестов "пример"
Ответ 3
Немного не по теме, однако, когда иногда приходится сравнивать коллекции чисел с плавающей запятой, используя сравнение с допуском, этот фрагмент может быть полезен:
// 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);
Ответ 4
Вы можете использовать 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
сообщит вам индекс несогласованных элементов, а также содержимое двух коллекций, предполагая, что две коллекции имеют одинаковый размер. Если они имеют разные размеры, то это считается несоответствием и печатаются разные размеры.
Ответ 5
Так как Boost 1.59 намного проще сравнивать экземпляры std::vector
. См. эту документацию для версии 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() );