【问题标题】:C++ unit testing framework with type and value parametrisation具有类型和值参数化的 C++ 单元测试框架
【发布时间】:2019-03-06 12:35:31
【问题描述】:

我正在寻找一个允许同时传递类型和值参数来测试功能的单元测试框架。

示例:假设我有一些模板排序功能:

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())

如果向量大小为 0、1、10 等,则 makeRandomVector 使用不同大小的参数来测试这些函数。

所以我正在寻找 C++ 单元测试框架,它允许创建可以同时接受类型 (int,MyCustomStruct) 和值参数 (0,1,10) 的测试,并对笛卡尔积的每个元素执行测试类型 x 值。

【问题讨论】:

  • 这里是一个起点。 en.wikipedia.org/wiki/List_of_unit_testing_frameworks,如果您能提供有关您的开发环境的更多详细信息,那就太好了。
  • 我认为 Catch2 是您正在寻找的:github.com/catchorg/Catch2/blob/master/docs/…
  • 我花了很多时间才明白 Google 测试无法满足我的需求。需要对特定测试框架有很好的了解才能回答我的问题,这就是我在这里提出问题的原因
  • 从我读到的 Catch2 只允许类型而不是类型和值参数化。强硬我可能是错的
  • 关于开发环境:我愿意为 Linux 和 Windows 免费设置任何可用的东西。目前我在 Windows 上使用 Qt creator。

标签: c++ unit-testing


【解决方案1】:

一种可能的方式是 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);
    ...
}

组合学

现在我们的问题是如何简单地构造类型和大小的所有组合。 我昨天刚刚用这个问题回答了almost same question。 在当前情况下,所有可能的{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&lt;std::tuple&lt;int, MyCustomStruct&gt;, 0, 1, 10&gt;等于std::tuple&lt;Case&lt;int,0&gt;, Case&lt;int,1&gt;, Case&lt;int,10&gt;, Case&lt;MyCustomStruct,0&gt;, ...&gt;的类型:

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&lt;...&gt; 分成一个类型列表,在这里我应用Nawaz 的简单一个。 那么所有的测试都可以如下进行:

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);
    ...
}

【讨论】:

  • 哇!您是如何使用模板生成所有类型/值组合的,真是令人惊讶。我正在学习模板编程,你的代码看起来很有教育意义。非常感谢您展示这种很酷的方法。
  • @xevepisis 多谢 :)。我已经检查过这种方法在我的 Windows 环境中是否有效。
猜你喜欢
  • 2010-09-10
  • 1970-01-01
  • 2012-05-02
  • 2012-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多