Модуль модульного тестирования C ++ с параметризацией типа и значения - PullRequest
1 голос
/ 06 марта 2019

Я ищу среду модульного тестирования, которая позволяет одновременно передавать параметры типа и значения для тестирования функции.

Пример: допустим, у меня есть несколько функций сортировки шаблонов:

template<class ITERATOR, class COMPARATOR = std::less<typename std::iterator_traits<ITERATOR>::value_type>>
void selectionSort(const ITERATOR first,const ITERATOR last, const COMPARATOR comparator = COMPARATOR ()){ ... };

template<class ITERATOR, class COMPARATOR = std::less<typename std::iterator_traits<ITERATOR>::value_type>>
void insertionSort(const ITERATOR first,const ITERATOR last, const COMPARATOR comparator = COMPARATOR ()) { ... }

, и я хочу протестировать эти функции с различными типами ввода, такими как:

template<class T>
vector<T> makeRandomVector(int size){ ... }

vector<int> intVec = makeRandomVector<int>(10);  //10 is vector size
someSort(intVec.begin(),intVec.end())
vector<MyCustomStruct> structVec = makeRandomVector<MyCustomStruct>(10);  
someSort(structVec.begin(),structVec.end())

ис аргументами разного размера для makeRandomVector для проверки этих функций, если размер вектора равен 0,1,10 и т. д.

Поэтому я ищу C ++ каркас модульного тестирования, который позволяет создавать тесты, которые будут принимать тип (int, MyCustomStruct) и значения параметров (0,1,10) одновременно и выполнить проверку для каждого элемента декартового произведения типов х значений.

1 Ответ

2 голосов
/ 06 марта 2019

Возможным способом является типизированный тест GoogleTest следующим образом.Обратите внимание, что это решение для C ++ 14 и более, и целочисленные параметры, как ваш пример {0, 1, 10}.


Подход

Позвольте намопределите следующую структуру Case:

template<typename T, std::size_t I>
struct Case
{
    using type = T;
    static constexpr std::size_t size = I;
};

Основная идея тестирования всех комбинаций типов и размеров заключается в использовании этой структуры для определения типов теста, таких как:

#include <gtest/gtest.h>

template <typename T>
class TypedTest : public ::testing::Test {};

using TestTypes = ::testing::Types<Case<int, 0>, Case<int, 1>, Case<int, 10>, Case<MyCustomStruct, 0>, ...>;

TYPED_TEST_CASE(TypedTest, TestTypes);

TYPED_TEST(TypedTest, sort) 
{
    auto vec = makeRandomVector<TypeParam::type>(TypeParam::size);
    ...
}

Комбинаторика

Теперь наша проблема заключается в том, как просто построить все комбинации типов и размеров.Я только что ответил почти на тот же вопрос с этой проблемой вчера.В текущем случае все возможные пары {int, MyCustomStruct} и {0, 1, 10} помечены одномерными целыми числами 0,1, ..., 5 следующим образом (и подход max66 также возможен):

0 -> (0/3, 0%3) = (0,0) -> std::tuple<int,  0>
1 -> (1/3, 1%3) = (0,1) -> std::tuple<int,  1>
2 -> (2/3, 2%3) = (0,2) -> std::tuple<int, 10>
3 -> (3/3, 3%3) = (1,0) -> std::tuple<MyCustomStruct,  0>
4 -> (4/3, 4%3) = (1,1) -> std::tuple<MyCustomStruct,  1>
5 -> (5/3, 5%3) = (1,2) -> std::tuple<MyCustomStruct, 10>

, где 3 - размер {0, 1, 10}.Это просто и понятно написать функцию, которая делает все возможные комбинации с этим алгоритмом следующим образом.Например, Combinations<std::tuple<int, MyCustomStruct>, 0, 1, 10> соответствует типу std::tuple<Case<int,0>, Case<int,1>, Case<int,10>, Case<MyCustomStruct,0>, ...>:

template<typename TupleType, typename TupleIdx, std::size_t I>
struct make_case
{
    static constexpr std::size_t N = std::tuple_size<TupleIdx>::value;

    using type = Case<typename std::tuple_element<I/N, TupleType>::type,
                               std::tuple_element<I%N, TupleIdx >::type::value>;
};

template <typename T1, typename T2, typename Is>
struct make_combinations;

template <typename TupleType, typename TupleIdx, std::size_t... Is>
struct make_combinations<TupleType, TupleIdx, std::index_sequence<Is...>>
{
    using tuples = std::tuple<typename make_case<TupleType, TupleIdx, Is>::type...>;
};

template<typename TupleTypes, std::size_t ...Is>
using Combinations = typename make_combinations
                       <TupleTypes,
                        std::tuple<std::integral_constant<std::size_t, Is>...>,
                        std::make_index_sequence<(std::tuple_size<TupleTypes>::value)*(sizeof...(Is))>>
                     ::tuples;

Тестирование

Применение ответов этого post , мы можем разбить этот кортеж Combinations<...> на список типов, и здесь я применяю простой способ Наваза.Тогда все тесты можно сделать следующим образом:

template<typename T>
struct Test;

template<typename ...T>
struct Test<std::tuple<T...>>
{
    using Types = ::testing::Types<T...>;
};

template <typename T>
class TypedTest : public ::testing::Test {};

using TestTypes = Test<Combinations<std::tuple<int, MyCustomStruct>, 0, 1, 10>>::Types;

TYPED_TEST_CASE(TypedTest, TestTypes);

TYPED_TEST(TypedTest, sort) 
{
    auto vec = makeRandomVector<TypeParam::type>(TypeParam::size);
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...