How to Use Type-Parameterized Tests in GoogleTest: A Complete Guide
GoogleTest enables type-parameterized tests through the TYPED_TEST_P and INSTANTIATE_TYPED_TEST_SUITE_P macros, allowing you to define test logic once and execute it against multiple C++ types while maintaining separate compilation for the test suite definition and its type instantiations.
Type-parameterized tests in GoogleTest eliminate code duplication when validating template classes or type-dependent algorithms across different data types. According to the google/googletest source code, this pattern relies on a specific two-phase macro system defined in googletest/include/gtest/gtest.h that separates the test suite declaration from the concrete type list instantiation.
Step 1: Define a Test Fixture Template
Begin by creating a test fixture as a class template. Inherit from ::testing::Test and templatize on the type parameter you want to vary.
template <typename T>
class StackTest : public ::testing::Test {
protected:
void SetUp() override { stack_.push(T{1}); }
::testing::internal::TypedEq<T> typed_eq_; // optional helper
std::stack<T> stack_;
};
This fixture, as demonstrated in googletest/samples/sample6_unittest.cc, holds the test infrastructure that will be reused across every type in your type list.
Step 2: Declare the Test Suite with TYPED_TEST_SUITE_P
Use TYPED_TEST_SUITE_P (or the older TYPED_TEST_CASE_P) to declare the suite without fixing the type. This tells GoogleTest that the suite definition is pending and will be completed later.
TYPED_TEST_SUITE_P(StackTest);
Place this declaration in a header file if you intend to instantiate the suite in multiple translation units, following the pattern documented in docs/advanced.md.
Step 3: Write Tests Using TYPED_TEST_P
Define individual tests with the TYPED_TEST_P macro instead of TEST_F. Inside the test body, access the current type through the TypeParam alias.
TYPED_TEST_P(StackTest, IsNotEmpty) {
EXPECT_FALSE(this->stack_.empty());
}
TYPED_TEST_P(StackTest, PopsCorrectValue) {
TypeParam value = this->stack_.top();
this->stack_.pop();
EXPECT_TRUE(this->stack_.empty());
EXPECT_EQ(value, TypeParam{1});
}
Each TYPED_TEST_P registers a test that will be compiled once for every type in the instantiation list.
Step 4: Register the Tests with REGISTER_TYPED_TEST_SUITE_P
After defining all tests, call REGISTER_TYPED_TEST_SUITE_P to associate the test names with the suite. This macro is defined in googletest/include/gtest/gtest.h and creates the factory functions necessary for instantiation.
REGISTER_TYPED_TEST_SUITE_P(StackTest,
IsNotEmpty,
PopsCorrectValue);
The test names listed here must match exactly the names used in TYPED_TEST_P.
Step 5: Instantiate the Suite with INSTANTIATE_TYPED_TEST_SUITE_P
Finally, create concrete test cases by providing a prefix and the type list using INSTANTIATE_TYPED_TEST_SUITE_P. The prefix becomes part of the generated test case names in the output.
using MyTypes = ::testing::Types<int, double, std::string>;
INSTANTIATE_TYPED_TEST_SUITE_P(MyStackTests,
StackTest,
MyTypes);
This generates test cases named MyStackTests/StackTest.IsNotEmpty/0, MyStackTests/StackTest.IsNotEmpty/1, etc., where the index corresponds to the position in MyTypes.
How the Macros Work Under the Hood
In googletest/include/gtest/gtest.h, each macro expands to specialized template classes that implement the curiously recurring template pattern for test registration. TYPED_TEST_SUITE_P creates a unique identifier for the suite pattern, while REGISTER_TYPED_TEST_SUITE_P instantiates a TypeParameterizedTestSuite helper that validates the test list. When INSTANTIATE_TYPED_TEST_SUITE_P executes, it iterates over the ::testing::Types<> list and generates a distinct test factory for each type, ensuring the same test logic executes with different compile-time parameters while keeping the binary size optimized through template instantiation.
Summary
- Type-parameterized tests reuse test logic across multiple C++ types using the
_Pmacro family. - Declaration (
TYPED_TEST_SUITE_P) and definition (TYPED_TEST_P) typically reside in headers, while instantiation (INSTANTIATE_TYPED_TEST_SUITE_P) resides in.ccfiles. - TypeParam provides access to the current type inside test bodies.
- REGISTER_TYPED_TEST_SUITE_P is mandatory to link test names to the suite before instantiation.
- The implementation resides primarily in
googletest/include/gtest/gtest.hwith examples ingoogletest/samples/sample6_unittest.cc.
Frequently Asked Questions
What is the difference between TYPED_TEST and TYPED_TEST_P?
TYPED_TEST requires the type list to be visible in the same translation unit where tests are defined, using TYPED_TEST_SUITE without the _P suffix. TYPED_TEST_P enables you to define the test suite in a header file and instantiate it later in a source file with INSTANTIATE_TYPED_TEST_SUITE_P, providing better separation of concerns and reusability across multiple type lists.
How do I access the current type inside a type-parameterized test?
Use the TypeParam typedef, which is injected into the test class scope by the TYPED_TEST_P macro. This alias refers to the specific type currently under test from the ::testing::Types<> list provided during instantiation.
Can I instantiate the same test suite with different prefixes in the same binary?
Yes. You may call INSTANTIATE_TYPED_TEST_SUITE_P multiple times with different prefixes and type lists for the same test suite. Each call generates a distinct set of test cases, allowing you to group instantiations logically (e.g., MyStackTests for primitive types and ComplexStackTests for user-defined types) while reusing the same fixture and test definitions.
Where should I place the REGISTER_TYPED_TEST_SUITE_P call?
Place REGISTER_TYPED_TEST_SUITE_P in the same header or source file where you define the TYPED_TEST_P tests, typically after all test definitions for that suite. This macro must appear exactly once per test suite and before any INSTANTIATE_TYPED_TEST_SUITE_P calls that reference the suite, as it finalizes the test list for the pattern.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →