I want to test a template class with gtest. I read about TYPED_TEST
s 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?
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.
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.
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.
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.
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.
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:
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.
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());
}
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With