Как сравнить векторы с Boost.Test? - PullRequest
18 голосов
/ 22 октября 2010

Я использую 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 на двух векторах, но это также потребует большого количества шаблонов.

Есть ли более чистый способ сделать это?

Ответы [ 5 ]

32 голосов
/ 22 октября 2010

Использование 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 в сравнениях.

12 голосов
/ 06 июля 2013

Немного не по теме, однако, когда иногда нужно сравнить наборы чисел с плавающей точкой, используя сравнение с допуском , тогда этот фрагмент может быть полезен:

// 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);
10 голосов
/ 22 октября 2010

Как насчет 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 В тесте обнаружен сбойсюита "пример"

6 голосов
/ 29 марта 2017

Начиная с 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() );
5 голосов
/ 08 августа 2014

Вы можете использовать BOOST_REQUIRE_EQUAL_COLLECTIONS с std::vector<T>, но вы должны научить Boost.Test, как печатать std::vector, когда у вас есть вектор векторов или карта, значения которой являются векторами.Когда у вас есть карта, Boost.Test нужно научить печатать std::pair.Поскольку вы не можете изменить определение std::vector или std::pair, вы должны сделать это таким образом, чтобы определенный вами оператор вставки потока использовался Boost.Test, не являясь частью определения класса * 1009.*.Кроме того, этот метод полезен, если вы не хотите добавлять операторы вставки потоков в тестируемую систему просто для того, чтобы сделать 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 расскажет вам индекс несоответствующих элементов, а также содержимое двух коллекций, предполагая, что две коллекции имеют одинаковый размер.Если они имеют разные размеры, это считается несоответствием, и различные размеры печатаются.

...