GTest: требуется приспособление, когда TYPE_TESTING глобальные функции? - PullRequest
0 голосов
/ 06 сентября 2018

Я хочу протестировать некоторые глобальные шаблонные функции, используя TYPED_TEST. Следующий код работает, мне просто интересно, есть ли способ, которым я могу избавиться от тестового прибора, так как он, кажется, не нужен ..

#include <gtest/gtest.h>
#include <base/mathfunctions.h>

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

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

TYPED_TEST_CASE(MinTest, Implementations);

TYPED_TEST(MinTest, ReturnsMinimumValue) 
{
   EXPECT_EQ(Base::Min<TypeParam>(-5, 5), -5);
}

1 Ответ

0 голосов
/ 07 сентября 2018

... так как это не нужно

Это необходимо. Посмотрите на это самостоятельное упрощение вашего источника модульного теста (это делает бессмысленным название ReturnsMinimumValue, но это не имеет значения):

gtester.cpp

#include <gtest/gtest.h>

template<typename T>
struct foo {
    static T bar() {
        return 0;
    }
};

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

typedef ::testing::Types<int, float> Implementations;

TYPED_TEST_CASE(MinTest, Implementations);

TYPED_TEST(MinTest, ReturnsMinimumValue)
{
    EXPECT_EQ(foo<TypeParam>::bar(),0);
}
int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}

Скомпилируйте, скомпонуйте и запустите это:

$ g++ -Wall -Wextra -o gtester gtester.cpp -lgtest -pthread && ./gtester
[==========] Running 2 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 1 test from MinTest/0, where TypeParam = int
[ RUN      ] MinTest/0.ReturnsMinimumValue
[       OK ] MinTest/0.ReturnsMinimumValue (0 ms)
[----------] 1 test from MinTest/0 (0 ms total)

[----------] 1 test from MinTest/1, where TypeParam = float
[ RUN      ] MinTest/1.ReturnsMinimumValue
[       OK ] MinTest/1.ReturnsMinimumValue (0 ms)
[----------] 1 test from MinTest/1 (0 ms total)

[----------] Global test environment tear-down
[==========] 2 tests from 2 test cases ran. (0 ms total)
[  PASSED  ] 2 tests.

Теперь давайте предварительно обработаем исходный файл и предварительно обработаем предварительно обработанный вывод (потому что это не красиво):

$ g++ -E -P gtester.cpp | clang-format > gtester.ii

Посмотрите на последние 50 с лишним строк вывода:

gtester.ii

...
...
int RUN_ALL_TESTS() __attribute__((warn_unused_result));
inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); }
template <typename T> struct foo {
  static T bar() { return 0; }
};
template <class T> class MinTest : public testing::Test {};
typedef ::testing::Types<int, float> Implementations;
typedef ::testing::internal::TypeList<Implementations>::type
    gtest_type_params_MinTest_;
template <typename gtest_TypeParam_>
class MinTest_ReturnsMinimumValue_Test : public MinTest<gtest_TypeParam_> {
private:
  typedef MinTest<gtest_TypeParam_> TestFixture;
  typedef gtest_TypeParam_ TypeParam;
  virtual void TestBody();
};
bool gtest_MinTest_ReturnsMinimumValue_registered_ __attribute__((unused)) =
    ::testing::internal::TypeParameterizedTest<
        MinTest,
        ::testing::internal::TemplateSel<MinTest_ReturnsMinimumValue_Test>,
        gtest_type_params_MinTest_>::Register("",
                                              ::testing::internal::CodeLocation(
                                                  "gtester.cpp", 17),
                                              "MinTest", "ReturnsMinimumValue",
                                              0);
template <typename gtest_TypeParam_>
void MinTest_ReturnsMinimumValue_Test<gtest_TypeParam_>::TestBody() {
  switch (0)
  case 0:
  default:
    if (const ::testing::AssertionResult gtest_ar =
            (::testing::internal::EqHelper<(
                 sizeof(::testing::internal::IsNullLiteralHelper(
                     foo<TypeParam>::bar())) ==
                 1)>::Compare("foo<TypeParam>::bar()", "0",
                              foo<TypeParam>::bar(), 0)))
      ;
    else
      ::testing::internal::AssertHelper(
          ::testing::TestPartResult::kNonFatalFailure, "gtester.cpp", 19,
          gtest_ar.failure_message()) = ::testing::Message();
}
int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

Наши:

TYPED_TEST(MinTest, ReturnsMinimumValue)
{
    EXPECT_EQ(foo<TypeParam>::bar(),0);
}

расширяется до определения:

template <typename gtest_TypeParam_>
class MinTest_ReturnsMinimumValue_Test;

, который получен из шаблона:

template <class T> class MinTest;

который получен из:

testing::Test;

из которых MinTest_ReturnsMinimumValue_Test наследует:

virtual void TestBody();

и переопределяет его как:

void MinTest_ReturnsMinimumValue_Test<gtest_TypeParam_>::TestBody() {
  switch (0)
  case 0:
  default:
    if (const ::testing::AssertionResult gtest_ar =
            (::testing::internal::EqHelper<(
                 sizeof(::testing::internal::IsNullLiteralHelper(
                     foo<TypeParam>::bar())) ==
                 1)>::Compare("foo<TypeParam>::bar()", "0",
                              foo<TypeParam>::bar(), 0)))
      ;
    else
      ::testing::internal::AssertHelper(
          ::testing::TestPartResult::kNonFatalFailure, "gtester.cpp", 19,
          gtest_ar.failure_message()) = ::testing::Message();
}

, который реализует расширение:

EXPECT_EQ(foo<TypeParam>::bar(),0);

Другая среда тестирования может выполнять параметризованные тесты иначе, но это то, как это делает Googletest.

Полиморфная иерархия классов:

template <typename gtest_TypeParam_>
class MinTest_ReturnsMinimumValue_Test
    <-
template <class T> class MinTest
    <-
testing::Test

не генерируется из-за какого-либо предположения о тестируемом вызове (вызовах) метода полиморфны. foo<TypeParam>::bar(), конечно, нет. Полиморфный Иерархия классов создается потому, что таков базовый дизайн googletest.

...