Как сравнить векторы с boost.test?
-
10-10-2019 - |
Вопрос
Я использую тест Boost для модульного тестирования кода 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
На двух векторах, но это также потребует много шаблонов.
Есть ли более чистый способ сделать это?
Решение
Использовать 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 в сравнениях.
Другие советы
Однако немного не по теме, когда иногда нужно сравнить коллекции чисел с плавающей точкой, используя Сравнение с терпимостью тогда этот фрагмент может быть полезен:
// 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);
Как насчет 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": check {col1, col1+7} == {col2, col2+7} не удалось.
Несоответствие в позиции 2: 3! = 4
Несоответствие в позиции 5: 6! = 7
* 1 сбой, обнаруженный в тестовом наборе "Пример"
Поскольку 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() );
Вы можете использовать BOOST_REQUIRE_EQUAL_COLLECTIONS
с std::vector<T>
, но вы должны научить Boost.test, как печатать std::vector
Когда у вас есть вектор векторов или карта, значения которых являются векторами. Когда у вас есть карта, Boost.test нужно научить, как печатать std::pair
. Анкет Поскольку вы не можете изменить определение std::vector
или же std::pair
, вы должны сделать это таким образом, чтобы оператор вставки потока, который вы определяете std::vector
. Анкет Кроме того, этот метод полезен, если вы не хотите добавлять операторов вставки потока в тестируемую систему, чтобы сделать Boost.test Happy.
Вот рецепт для любого 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
Расскажу вам индекс несоответствующих предметов, а также содержимое двух коллекций, предполагая, что две коллекции имеют одинакового размера. Если они имеют разные размеры, то это считается несоответствием, а разные размеры напечатаны.