Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test c++ template class with multiple template parameters using gtest?

I want to test a template class with gtest. I read about TYPED_TESTs in gtest manual and looked at the official example (samples\sample6_unittest.cc) they reference. This template from the example has only one template parameter. But, my code has two template parameters, how can I test it?

I have the following code:

// two element type
template <typename E, typename F>
class QueueNew
{
public:
    QueueNew() {}
    void Enqueue(const E& element) {}
    E* Dequeue() {}
    F size() const 
    {
        return (F)123;
    }
};

for which I wrote the test code below:

template <class E, class F>
QueueNew<E, F>* CreateQueue();

template <>
QueueNew<int, int>* CreateQueue<int, int>()
{
    return new QueueNew < int, int > ;
}
template <>
QueueNew<char, char>* CreateQueue<char, char>()
{
    return new QueueNew < char, char > ;
}

template <class E, class F>
class QueueTestNew;

template <class E>
class QueueTestNew<E, int> : public testing::Test
{
protected:
    QueueTestNew() : queue(CreateQueue<E, int>()){}
    virtual ~QueueTestNew(){ delete queue; }
    QueueNew<E, int>* const queue;
};

template <class E>
class QueueTestNew<char, E> : public testing::Test
{
protected:
    QueueTestNew() : queue(CreateQueue<char, E>()){}
    virtual ~QueueTestNew(){ delete queue; }
    QueueNew<char, E>* const queue;
};

// The list of types we want to test.
typedef ::testing::Types <char, int> Implementations;

TYPED_TEST_CASE(QueueTestNew, Implementations);

TYPED_TEST(QueueTestNew, DefaultConstructor)
{
    EXPECT_EQ(123u, this->queue->size());
}

but when building, I get the error:

error C2976: 'QueueTestNew' : too few template arguments
see declaration of 'QueueTestNew'
...

I think my test template method with gtest is wrong, so how should I do this?

like image 426
thinkerou Avatar asked Apr 01 '15 03:04

thinkerou


People also ask

Can we pass Nontype parameters to templates?

Template classes and functions can make use of another kind of template parameter known as a non-type parameter. A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument.

Can you have templates with two or more generic arguments?

Function Templates with Multiple ParametersYou can also use multiple parameters in your function template. The above syntax will accept any number of arguments of different types. Above, we used two generic types such as A and B in the template function.

Can a template be a template parameter?

Templates can be template parameters. In this case, they are called template parameters. The container adaptors std::stack, std::queue, and std::priority_queue use per default a std::deque to hold their arguments, but you can use a different container.

Should I use Parameterized Tests from googletest?

But using parameterized tests from GoogleTest is definitely an option you should consider.. We have two different ways to use this feature. One way is to build our tests from scratch and the other is to build them on the foundations of a FIXTURE like the one we already saw when we introduced a common leapYear variable.

What is the use of template arguments in JavaScript?

tells the compiler that the first argument is of type float and another one is int type. During creation of objects, constructor is called and values are received by template arguments. This article is contributed by Sakshi Tiwari.

How to pass more than one template argument to testwithparam<T>?

You cannot pass more than one template argument to TestWithParam<T>, but you can always pass a std::pair, or even better a std::tuple with as many members as you want. In this case, GetParam () retrieves tuples. In order to obtain an element of a tuple we can use std::get. Or we could even use structured bidings starting from C++17:

How to pass Parameterized Tests in unittest?

While for a normal unittest we use the TEST () macro and TEST_F () for a fixture, we have to use TEST_P () for parameterized tests. As the first parameter, we have to pass the name of the test class and as the second we just have to pick a good name for what our tests represent.


2 Answers

A trick would be to make gtest see a single type parameter, with nested types. To do this, you can define a templated structure such as:

template <typename A, typename B>
struct TypeDefinitions
{
  typedef typename A MyA;
  typedef typename B MyB;
};

Which you can pass to your typed-test fixture:

template <class T>
class QueueTestNew : public testing::Test
{
protected:
  QueueTestNew() : queue(CreateQueue<typename T::MyA, typename T::MyB>()){}
  virtual ~QueueTestNew(){ delete queue; }
  QueueNew<typename T::MyA, typename T::MyB>* const queue;
};

// The list of types we want to test.
typedef ::testing::Types <TypeDefinitions<char,char>,
                          TypeDefinitions<int,int> > Implementations;

TYPED_TEST_CASE(QueueTestNew, Implementations);

TYPED_TEST(QueueTestNew, DefaultConstructor)
{
  typename TypeParam::MyA someA; // if you need access to the subtypes in the test itself

  EXPECT_EQ(123u, this->queue->size());
}
like image 151
SleuthEye Avatar answered Oct 12 '22 07:10

SleuthEye


An example that might also work, and doesn't require a custom struct, is using std::tuples

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

typedef ::testing::Types <std::tuple<float64_t, float32_t, int16>, std::tuple<int64, int8, float32_t> > Implementations;

TYPED_TEST_CASE(TestThreeParams, Implementations);

TYPED_TEST(TestThreeParams, MaximumTest)
{
    using A = std::tuple_element<0, decltype(TypeParam())>::type;
    using B = std::tuple_element<1, decltype(TypeParam())>::type;
    using C = std::tuple_element<2, decltype(TypeParam())>::type;

    bool test = (Max<A, B, C>(A(-5), B(2), C(5)) == 5);
    EXPECT_TRUE(test);
}
like image 11
Ben Avatar answered Oct 12 '22 06:10

Ben