You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为GTest生成模板参数全组合以简化测试用例扩展

解决GTest中模板类多枚举参数全组合自动生成问题

问题背景

现有枚举类、模板类及GTest测试代码如下:

枚举类定义

enum class first{
    a,
    b
};

enum class second{
    c,
    d
};

// 可扩展的第三个枚举(示例)
enum class third { e, f };

模板类定义

template<first N, second M> class A{
public:
    A(){}
    A(int n) {
        var = n;
    }
    int var;
};

// 扩展支持三个参数的模板类(示例)
template<first N, second M, third K> class A3{
public:
    A3(){}
    A3(int n) {
        var = n;
    }
    int var;
};

当前测试代码痛点

现有测试用例需要手动枚举所有A的模板参数组合,新增枚举值时需修改MyTypes列表,扩展性差:

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

TYPED_TEST_CASE_P(TestA);

TYPED_TEST_P(TestA, SomeTest){
    TypeParam x(0);
    EXPECT_EQ(x.var,0);
}

REGISTER_TYPED_TEST_CASE_P(TestA, SomeTest);

// 手动维护组合,扩展性差
typedef ::testing::Types<A<first::a, second::c>, A<first::b, second::d>> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, TestA, MyTypes);

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

需求:自动生成所有枚举参数的笛卡尔积组合,支持2个及以上模板参数,新增枚举值时仅需更新对应参数列表,无需修改测试用例逻辑。


解决方案:模板元编程实现自动组合

通过C++模板元编程实现参数列表的笛卡尔积生成,将每个枚举的所有值封装为类型列表,再组合成A的实例类型列表,最终集成到GTest中。

步骤1:封装枚举值为类型

定义模板类将枚举值转换为类型(GTest的Types仅接受类型参数):

template <auto Val>
struct EnumWrapper {
    static constexpr auto value = Val; // 暴露枚举值
};

步骤2:定义各枚举的全值类型列表

将每个枚举的所有值封装为::testing::Types类型列表,新增枚举值时仅需在此处添加:

// first枚举的全值列表
using FirstEnumList = ::testing::Types<
    EnumWrapper<first::a>,
    EnumWrapper<first::b>
    // 新增first枚举值时直接追加,如EnumWrapper<first::c>
>;

// second枚举的全值列表
using SecondEnumList = ::testing::Types<
    EnumWrapper<second::c>,
    EnumWrapper<second::d>
    // 新增second枚举值时直接追加
>;

// third枚举的全值列表(示例)
using ThirdEnumList = ::testing::Types<
    EnumWrapper<third::e>,
    EnumWrapper<third::f>
>;

步骤3:实现笛卡尔积组合逻辑

二元组合(两个枚举参数)

// 辅助模板:将单个枚举类型与另一枚举列表组合
template <typename SingleEnum, typename EnumList>
struct CombineSingleWithList;

// 展开列表的特化
template <typename SingleEnum, template <typename...> typename List, typename... Enums>
struct CombineSingleWithList<SingleEnum, List<Enums...>> {
    // 生成SingleEnum与每个Enums组合后的A类型列表
    using type = ::testing::Types<
        A<SingleEnum::value, Enums::value>...
    >;
};

// 辅助模板:两个枚举列表的笛卡尔积
template <typename List1, typename List2>
struct CombineTwoLists;

// 展开第一个列表的特化
template <template <typename...> typename List, typename... Enums1, typename List2>
struct CombineTwoLists<List<Enums1...>, List2> {
    // 依次将List1中的每个元素与List2组合,再合并为一个大列表
    using type = ::testing::Types<
        typename CombineSingleWithList<Enums1, List2>::type::value_type...
    >;
};

多元组合(三个及以上枚举参数)

基于二元组合扩展,递归实现多列表的笛卡尔积:

// 多元组合递归模板
template <typename... EnumLists>
struct CombineMultiLists;

// 递归终止条件:单个列表直接返回
template <typename EnumList>
struct CombineMultiLists<EnumList> {
    using type = EnumList;
};

// 递归步骤:先组合前n-1个列表,再与第n个列表组合
template <typename FirstList, typename... RestLists>
struct CombineMultiLists<FirstList, RestLists...> {
    using type = typename CombineTwoLists<
        typename CombineMultiLists<FirstList>::type,
        typename CombineMultiLists<RestLists...>::type
    >::type;
};

// 针对三参数模板类A3的单元素组合逻辑(示例)
template <typename SingleEnum, typename EnumList>
struct CombineSingleWithList3;

template <typename SingleEnum, template <typename...> typename List, typename... Enums>
struct CombineSingleWithList3<SingleEnum, List<Enums...>> {
    using type = ::testing::Types<
        A3<SingleEnum::value, Enums::value, typename Enums::value...>
    >;
};

步骤4:集成到GTest测试用例

生成所有组合的类型列表,直接传入INSTANTIATE_TYPED_TEST_CASE_P:

// 生成两个枚举参数的所有组合
using AllTwoParamCombinations = typename CombineTwoLists<FirstEnumList, SecondEnumList>::type;

// 生成三个枚举参数的所有组合(示例)
using AllThreeParamCombinations = typename CombineMultiLists<FirstEnumList, SecondEnumList, ThirdEnumList>::type;

// 实例化双参数测试用例
INSTANTIATE_TYPED_TEST_CASE_P(AllTwoParamTests, TestA, AllTwoParamCombinations);

// 针对三参数模板类的测试用例(示例)
template<typename T> class TestA3 : public ::testing::Test {};
TYPED_TEST_CASE_P(TestA3);
TYPED_TEST_P(TestA3, SomeTest3){
    TypeParam x(0);
    EXPECT_EQ(x.var,0);
}
REGISTER_TYPED_TEST_CASE_P(TestA3, SomeTest3);
INSTANTIATE_TYPED_TEST_CASE_P(AllThreeParamTests, TestA3, AllThreeParamCombinations);

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

扩展说明

  • 新增枚举值:仅需在对应枚举的类型列表(如FirstEnumList)中追加EnumWrapper<新枚举值>,无需修改测试用例逻辑。
  • 扩展更多参数:只需新增对应枚举的类型列表,修改CombineSingleWithList模板以适配新的模板类参数数量,再通过CombineMultiLists组合即可。

内容的提问来源于stack exchange,提问作者三顿饭

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 04:45:30