Maxim Kuzmin
Maxim Kuzmin

Reputation: 11

Value and type parametrised google tests together c++

I want to test a template function on a range of values and a range of types. So something like

template <class T>
void foo(Bar<T>&);

But the issue is I can't get the google test's value parametrised tests to work with template test suite. Most of my tests currently look like this:

TYPED_TEST(FooTest, foo) {
  for (int repeats = 0 ...) { // don't want this
    Bar<TypeParam> bar;

    for (... i < repeats ...)
      foo(bar);

    EXPECT_EQ(bar, /*...*/);
  }
}

So I am looking for a way to get rid of that first for loop and pass repeats as a const parameter instead. And just in case you are wondering here is the real test file. Although its not entirely this way right now because I am refactoring this code.

I have tried this so far:

using NumericTypes = ::testing::Types<uint8_t /*...*/ >;

template <class T>
class FooTest
  : public ::testing::TestWithParam<const int> { };
  
TYPED_TEST_SUITE(FooTest,
  NumericTypes,
  TestingTypenames);
  
INSTANTIATE_TEST_SUITE_P(SomeFooTest,
  FooTest,
  testing::Range(0,3));

The error I am getting:

foo.cpp: error: template argument 1 is invalid
   16 |   INSTANTIATE_TEST_SUITE_P(SomeFooTest,
      |   ^~~~~~~~~~~~~~~~~~~~~~~~

So these type parametrized tests are making wonders for me its just the for loops that are bothering me. And in the new tests I am writing there would be 3 layers of for loops because I am testing nested lists and they will behave differently if they are nested.

Upvotes: 1

Views: 1583

Answers (1)

Etienne Laurin
Etienne Laurin

Reputation: 7184

If you can, it is much easier either to pass your values as template arguments or to pass your types as values.

An example with values as template arguments:

#include <variant>
#include <gtest/gtest.h>

template<typename T, T value>
struct param1 {
    static T get(){ return value; }
};

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

using params = ::testing::Types<
  param1<uint8_t, 0>,
  param1<uint8_t, 1>,
  param1<uint16_t, 0>
>;

TYPED_TEST_SUITE(example1, params);

TYPED_TEST(example1, test) {
    ASSERT_TRUE(TypeParam::get() < 2);
}

And with types as values:

using param2 = std::variant<uint8_t, uint16_t>;

class example2 : public ::testing::TestWithParam<param2> {};

INSTANTIATE_TEST_SUITE_P(foo, example2, testing::Values<param2>(
    uint8_t(0),
    uint8_t(1),
    uint16_t(0)
));

TEST_P(example2, test) {
    std::visit([&](auto value){
        ASSERT_TRUE(value < 2);
    }, GetParam());
}

Upvotes: 1

Related Questions