I want to unit-test some global templated functions using TYPED_TEST
. The following code works, I just wonder whether there is way I can get rid of the test fixture, as it does not seem to be needed..
#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);
}
... as it does not seem to be needed
It is needed. See this self-contained simplification of your unit-test source
(it makes nonsense of the name ReturnsMinimumValue
, but that doesn't matter):
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();
}
Compile, link and run that:
$ 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.
Now let's preprocess the source file, and prettify the preprocessed output (because it's not pretty):
$ g++ -E -P gtester.cpp | clang-format > gtester.ii
Look at the the last 50-odd lines of the output:
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();
}
Our:
TYPED_TEST(MinTest, ReturnsMinimumValue)
{
EXPECT_EQ(foo<TypeParam>::bar(),0);
}
expands to the definition of:
template <typename gtest_TypeParam_>
class MinTest_ReturnsMinimumValue_Test;
which is derived from the template fixture:
template <class T> class MinTest;
which is derived from:
testing::Test;
from which MinTest_ReturnsMinimumValue_Test
inherits:
virtual void TestBody();
and overrides it as:
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();
}
which implements the expansion of:
EXPECT_EQ(foo<TypeParam>::bar(),0);
A different test framework might accomplish type-parameterised test cases differently, but this is how googletest does it.
The polymorphic class hierarchy:
template <typename gtest_TypeParam_>
class MinTest_ReturnsMinimumValue_Test
<-
template <class T> class MinTest
<-
testing::Test
is not generated because of any presumption the method call(s) under test
are polymorphic. foo<TypeParam>::bar()
, of course, is not. The polymorphic
class hierarchy is generated because such is the basic design of googletest.