我正在寻找一种使用Catch测试模板类的好方法。我有一些几乎可行的东西:
#define RUN_ALL(fn, params) \
fn<uint8_t, bool>(params); \
fn<uint8_t, char>(params); \
fn<uint16_t, bool>(params); \
fn<uint16_t, char>(params); \
fn<uint32_t, bool>(params); \
fn<uint32_t, char>(params); \
fn<uint64_t, bool>(params); \
fn<uint64_t, char>(params);
template<typename A, typename B>
void test_number_one() {
REQUIRE(...)
}
TEST_CASE("Foo::Foo() works nicely", "[SmallGraph]") {
RUN_ALL(test_number_one)
}
此设置仅在第一次失败时运行,这很好,因为很可能所有8种情况都会以相同的方式失败。但是,知道在发生故障时使用哪组模板参数会很好。我的想法是这样做:
#define RUN_ALL_P(fn, params) \
INFO("Testing <uint8_t, bool>"); \
fn<uint8_t, bool>(params); \
INFO("Testing <uint8_t, char>"); \
fn<uint8_t, char>(params); \
INFO("Testing <uint16_t, bool>"); \
fn<uint16_t, bool>(params); \
...
但是,我不能在RUN_ALL中使用多个INFO,因为这样做会生成带有重复标识符的代码。
FOO.cpp:270:3: error: redefinition of 'scopedMessage270'
RUN_ALL(test_number_one);
(RUN_ALL(test_number_one)
出现在第270行。)
对于不需要所有测试功能到同一签名的变通方法的任何想法?
(我也欢迎指向使用CATCH测试模板代码的文章,以及如何搜索这些文章的建议,而不会得到一些关于一般异常处理的结果 - 即try / catch。)
答案 0 :(得分:1)
宏的问题在于,当它被展开时,它会扩展为一行。虽然我不知道你的测试框架在使用中,很明显宏可以做到与此类似的东西:
struct M { M(char* msg) { puts(msg); } }; // just an example class...
#define INFO(m) M scopedMessage##__line__(msg)
因此,如果在第270行使用宏RUN_ALL,您将获得多个scopedMessage270实例...
您可以通过使用模板替换宏来解决此问题。不幸的是,您不能将它与模板函数一起使用,因此您还必须制作测试用例模板类:
template <template <typename T, typename TT > class Test >
struct All
{
template <typename ... Parameters>
static void run(Parameters ... parameters)
{
Test<uint8_t, bool>::run(parameters ...);
Test<uint8_t, char>::run(parameters ...);
Test<uint16_t, bool>::run(parameters ...);
Test<uint16_t, char>::run(parameters ...);
Test<uint32_t, bool>::run(parameters ...);
Test<uint32_t, char>::run(parameters ...);
Test<uint64_t, bool>::run(parameters ...);
Test<uint64_t, char>::run(parameters ...);
}
};
template<typename A, typename B>
struct test_number_one
{
static void run()
{
// log test name
// run the test
}
};
template<typename A, typename B>
struct test_number_two
{
static void run(int n)
{
// log test name and parameter value
// run the test
}
};
int main(int argc, char* argv[])
{
All<test_number_one>::run();
All<test_number_two>::run(12);
All<test_number_two>::run(10);
}
现在,在模板中,所有代码行都保留在不同的行中,您可以根据需要放置在任何日志记录之间:
template <typename ... Parameters>
static void run(Parameters ... parameters)
{
INFO("uint8_t, bool");
Test<uint8_t, bool>::run(parameters ...);
INFO("uint8_t, char");
Test<uint8_t, char>::run(parameters ...);
// ...
答案 1 :(得分:1)
@Aconcagua绝对正确。我的解决方案类似,但使用仿函数(由@R Sahu建议--- C++ Single function pointer for all template instances)
template<template<typename, typename> class TestFunctor, typename... Parameters>
void testAllTypes(Parameters... parameters) {
INFO("Testing <uint8_t, bool>");
TestFunctor<uint8_t, bool>()(parameters...);
INFO("Testing <uint8_t, char>");
TestFunctor<uint8_t, char>()(parameters...);
// ...
}
template<typename A, typename B>
struct testDefaultConstructor {
void operator()() {
mallGraph<A, B> sg;
REQUIRE(sg.numVertices() == 0);
REQUIRE_FALSE(sg.edgecountIsValid());
REQUIRE_FALSE(sg.adjacencyMatrixIsValid());
}
};
TEST_CASE("SmallGraph::SmallGraph() initializes instance data as expected", "[SmallGraph]") {
testAllTypes<testDefaultConstructor>();
}