【问题标题】:Test multiple template functions with gTest使用 gTest 测试多个模板函数
【发布时间】:2017-04-06 12:40:57
【问题描述】:

如果有以下3个模板函数:

template <typename T, size_t SIZE>
size_t foo1(array<T, SIZE>& a, size_t start){}

template <typename T, size_t SIZE>
size_t foo2(array<T, SIZE>& a, size_t start){}

template <typename T, size_t SIZE>
size_t foo3(array<T, SIZE>& a, size_t start){}

这三个都对数组 a 执行相同的操作,但实现方式不同。

现在我喜欢为所有三个函数设置一个谷歌测试,但没有 C'n'P 所有测试本身。我读过“值参数化测试”,但我无法在模板函数本身上定义指针。

测试可能如下所示:

TEST(Foo1, t1) {
    std::array<int, 2> arr = {3,1};
    EXPECT_EQ(1, arr[foo1(arr, 0)]);
}

TEST(Foo2, t1) {
    std::array<int, 2> arr = {3,1};
    EXPECT_EQ(1, arr[foo2(arr, 0)]);
}

TEST(Foo3, t1) {
    std::array<int, 2> arr = {3,1};
    EXPECT_EQ(1, arr[foo3(arr, 0)]);
}

(如何)是否可以为所有三个模板函数设置测试用例并重用其测试,而无需将测试包装在自定义函数中(仅使用 gTest)?

我只喜欢定义一次测试并将使用的函数作为某种测试参数“传递”给测试。

提前致谢:-)


编辑 1:

经过长时间的尝试,我运行了这个:

template<typename T, size_t SIZE>
using fooFp = size_t (*)(std::array<T, SIZE>&, size_t);

template <typename T, size_t SIZE>
class fooTemplateClass: public ::testing::TestWithParam<fooFp<T, SIZE>> {};

class Tc1 : public fooTemplateClass<int, 1>{};

TEST_P(Tc1 , Fnc) {
    fooFp<int, 1> fnc = GetParam();
    std::array<int, 1> arr = {1};
    EXPECT_EQ(1, arr[fnc(arr, 0)]);
}

INSTANTIATE_TEST_CASE_P(Name, Tc1, ::testing::Values(foo1<int, 1>, foo2<int, 1>, foo3<int, 1>), );

但是,这仍然不方便,因为我需要为每个模板组合定义一个类(在这种情况下为 Tc1)。我也不喜欢我需要在 INSTANTIATE_TEST_CASE_P 中定义所有模板设置。

有没有办法概括这个,所以我只需要写这样的东西:

TEST_P(fooTemplateClass<int, 1>, Fnc) {
    std::array<int, 1> arr = {1};
    fooFp<int, 1> fnc = GetParam();
    EXPECT_EQ(1, arr[fnc(arr, 0)]);
}

INSTANTIATE_TEST_CASE_P(Name, fooTemplateClass, ::testing::Values(foo1, foo2, foo3), );

我在编译时知道所有模板类型和大小,因此我可以传递它们。但目前我不知道如何将模板类传递给 TEST_P 宏......

【问题讨论】:

    标签: c++ templates googletest


    【解决方案1】:

    目前手头没有 gtest 来测试它,但我认为您可以使用源自 ::testing::TestWithParam&lt;std::function&lt;size_t(std::array&lt;T, SIZE&gt;, size_t)&gt;&gt; 的单个测试夹具。这使您可以使用TEST_P 宏编写测试,该宏可以调用GetParam() 来获取std::function&lt;size_t(std::array&lt;T, SIZE&gt;, size_t)&gt; 类型的实例。然后你可以使用这个函数对象来调用你的方法。

    但是,由于您的 T 和 SIZE 模板参数,您的测试夹具仍然是模板类。第一个问题是,如果宏参数中没有括号括起来,则不能在宏参数中包含 ,。这可以通过编写自己的定义 typedef 的宏并利用可变参数宏来规避。但是,您需要根据模板参数唯一标识每个 typedef,以便稍后将其传递给 INSTANTIATE_TEST_CASE_P。但是,这需要一些我无法做到的高级模板技巧。

    以下代码为您提供了一个宏TEST_T,可以如图所示使用

    #define CONCAT(a, b) CONCAT_(a,b)
    #define CONCAT_(a,b) a ## b
    #define ARG(arg1, ...) arg1
    #define ARG1(arg, ...) CONCAT(arg, ARG( __VA_ARGS__ ))
    #define ARG2(arg, ...) CONCAT(arg, ARG1( __VA_ARGS__ ))
    #define ARG3(arg, ...) CONCAT(arg, ARG2( __VA_ARGS__ ))
    
    #define TEST_T(test_case_name, test_name, ...) \
        using CONCAT(test_case_name, ARG2( __VA_ARGS__ )) = test_case_name < __VA_ARGS__ >; \
        TEST_P(CONCAT(test_case_name, ARG2( __VA_ARGS__ )), test_name)
    
    TEST_T(fooTemplateClass, Fnc, int, 1) {
        fooFp<int, 1> fnc = GetParam();
        std::array<int, 1> arr = {1};
        EXPECT_EQ(1, arr[fnc(arr, 0)]);
    }
    

    你仍然需要实例化它

    INSTANTIATE_TEST_CASE_P(Name, fooTemplateClassint1, ::testing::Values(foo1<int, 1>, foo2<int, 1>, foo3<int, 1>));
    

    我无法解决剩下的问题,但也许它可以帮助您找到适合您需求的解决方案。

    【讨论】:

    • 感谢您的建议。我已经尝试过了,但似乎它不起作用。我已经编辑了我的原始帖子。
    • 第一个问题是,你不能在宏参数中有,,因为它没有被括号括起来。这可以通过编写自己的定义 typedef 的宏并利用可变参数宏来规避。但是,您需要根据模板参数唯一标识每个 typedef,以便稍后将其传递给 INSTANTIATE_TEST_CASE_P。但是,这需要一些我无法做到的高级模板技巧。我玩了几个小时,但无法修复它。但是,我更新了我的答案...
    猜你喜欢
    • 1970-01-01
    • 2018-07-18
    • 2022-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-21
    相关资源
    最近更新 更多