Create gtest value parametrized test for a template class
Asked Answered
O

2

7

I have a template class of type

<size_t N>
class Line {
   ...
};

How could I could I create a test for several instances of this class? e.g. Line<1>, Line<2>, ...

I have checked the documentation and there are:

  • Value-Parametrized tests, for run-time values

  • Type-Parametrized tests, which allow you to change the typename at compile time.

However, I do not find anything to change values at compile-time.

Obstipation answered 7/2, 2018 at 16:57 Comment(1)
I guess you can still create a template class which expects types defining a static constexpr T value as its template parameters ? That might be a bit tedious, but it should work at least. ( ideone.com/4l4H7y )Vann
B
8

Googletest has no ready-to-wear solution for generating tests over a template for a set of non-type template parameters, as you want.

Assuming C++11 or later, you can take advantage of std::integral_constant<T,N> to create a class that uniquely represents each of the range of std::size_t parameters N for which you want tests covering Line<N>, and use std::integral_constant<std::size_t,N> as a proxy for N to construct a TYPED_TEST_CASE and associated TYPED_TESTs. Like so:

A toy Line class for illustration:

Line.h

#ifndef LINE_H
#define LINE_H
#include <cstddef>

template <std::size_t N>
class Line {
public:
    static constexpr std::size_t capacity() {
        return N;
    }
    explicit Line(std::size_t n)
    : _length{n < N ? n : N}{};

    std::size_t length() const {
        return _length;
    }

private:
    std::size_t _length = 0;

};

#endif

Googletest test runner:

line_test.cpp

#include <gtest/gtest.h>
#include <type_traits>
#include "line.h"

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

using test_types = ::testing::Types<
    std::integral_constant<std::size_t,2>,
    std::integral_constant<std::size_t,3>, 
    std::integral_constant<std::size_t,5>>;

TYPED_TEST_CASE(line_tester, test_types);

TYPED_TEST(line_tester, get_capacity) {
    static constexpr std::size_t n = TypeParam::value;
    ASSERT_EQ(n,Line<n>::capacity());
}

TYPED_TEST(line_tester, set_length_preserved) {
    Line<TypeParam::value> line{1};
    ASSERT_EQ(line.length(),1);
}

TYPED_TEST(line_tester, set_length_trunctated) {
    static constexpr std::size_t n = TypeParam::value;
    Line<n> line{999};
    ASSERT_EQ(line.length(),Line<n>::capacity());
}

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Which runs like:

$ ./line_tester 
[==========] Running 9 tests from 3 test cases.
[----------] Global test environment set-up.
[----------] 3 tests from line_tester/0, where TypeParam = std::integral_constant<unsigned long, 2ul>
[ RUN      ] line_tester/0.get_capacity
[       OK ] line_tester/0.get_capacity (0 ms)
[ RUN      ] line_tester/0.set_length_preserved
[       OK ] line_tester/0.set_length_preserved (0 ms)
[ RUN      ] line_tester/0.set_length_trunctated
[       OK ] line_tester/0.set_length_trunctated (0 ms)
[----------] 3 tests from line_tester/0 (1 ms total)

[----------] 3 tests from line_tester/1, where TypeParam = std::integral_constant<unsigned long, 3ul>
[ RUN      ] line_tester/1.get_capacity
[       OK ] line_tester/1.get_capacity (0 ms)
[ RUN      ] line_tester/1.set_length_preserved
[       OK ] line_tester/1.set_length_preserved (0 ms)
[ RUN      ] line_tester/1.set_length_trunctated
[       OK ] line_tester/1.set_length_trunctated (0 ms)
[----------] 3 tests from line_tester/1 (0 ms total)

[----------] 3 tests from line_tester/2, where TypeParam = std::integral_constant<unsigned long, 5ul>
[ RUN      ] line_tester/2.get_capacity
[       OK ] line_tester/2.get_capacity (0 ms)
[ RUN      ] line_tester/2.set_length_preserved
[       OK ] line_tester/2.set_length_preserved (0 ms)
[ RUN      ] line_tester/2.set_length_trunctated
[       OK ] line_tester/2.set_length_trunctated (0 ms)
[----------] 3 tests from line_tester/2 (0 ms total)

[----------] Global test environment tear-down
[==========] 9 tests from 3 test cases ran. (1 ms total)
[  PASSED  ] 9 tests.
Bowie answered 11/2, 2018 at 15:32 Comment(0)
A
0

I was trying to resolve the same problem and came up with a slightly different solution. Perhaps it will be useful

#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <type_traits>

// The actual class to run the test on
template <std::size_t N>
class Line {
  public:
    explicit Line(){};

    std::size_t length() const {
        return length_;
    }

  private:
    static constexpr std::size_t length_{N};
};

template <typename T>
class line_tester : public ::testing::Test
{
  protected:
    static const size_t kRedundantCmdNum{3};

    line_tester() {}

    void SetUp()
    {
        // code here will execute just before the test ensues
    }

    void TearDown()
    {
        // code here will be called just after the test completes
        // ok to through exceptions from here if need be
    }

    virtual ~line_tester() {}

    typename T::value_type GetLineLength() { return line_.length();}

  private:
    Line<T::value> line_{};
};

using test_types = ::testing::Types<
    std::integral_constant<std::size_t,2>,
    std::integral_constant<std::size_t,3>,
    std::integral_constant<std::size_t,5>>;

TYPED_TEST_CASE(line_tester, test_types);

TYPED_TEST(line_tester, get_capacity) {
    static constexpr std::size_t n = TypeParam::value;
    ASSERT_EQ(n, this->GetLineLength());
}
Ankylostomiasis answered 10/11, 2022 at 1:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.