How to Define Type-Parameterized Tests in GoogleTest: 4 Macro Phases Explained
GoogleTest enables type-parameterized tests through four distinct macros—TYPED_TEST_SUITE_P, TYPED_TEST_P, REGISTER_TYPED_TEST_SUITE_P, and INSTANTIATE_TYPED_TEST_SUITE_P—that separate test pattern declaration from concrete type instantiation, allowing a single template-based test suite to run against multiple data types.
Type-parameterized tests eliminate redundancy when testing template classes or generic algorithms across different types. The implementation resides in googletest/include/gtest/gtest-typed-test.h and leverages static initialization to register test cases before main() executes. This guide explains how to define type-parameterized tests in GoogleTest using the exact macro expansion sequence found in the source code.
The Four-Phase Macro Architecture
GoogleTest implements type-parameterized testing through a strict four-phase workflow. Each phase corresponds to a specific macro in gtest-typed-test.h that expands into template machinery and static registration objects within the testing::internal namespace.
Phase 1: Declare the Pattern with TYPED_TEST_SUITE_P
Begin by declaring a test pattern using TYPED_TEST_SUITE_P(SuiteName). According to lines 59-61 of gtest-typed-test.h, this macro creates a static TypedTestSuitePState object that stores metadata about the tests that will belong to this pattern.
template <typename T>
class StackTest : public ::testing::Test {};
// Declares the pattern (lines 59-61)
TYPED_TEST_SUITE_P(StackTest);
The macro generates a unique namespace GTEST_SUITE_NAMESPACE_(SuiteName) to encapsulate pattern-specific declarations and initializes the registration state.
Phase 2: Define Test Bodies with TYPED_TEST_P
Use TYPED_TEST_P(SuiteName, TestName) to define individual test cases. As implemented in lines 70-84, this macro generates a templated test class inside the hidden namespace and registers the test name with the TypedTestSuitePState object created in Phase 1.
// Defines test bodies (lines 70-84)
TYPED_TEST_P(StackTest, IsEmpty) {
Stack<TypeParam> s;
EXPECT_TRUE(s.empty());
}
TYPED_TEST_P(StackTest, PushPop) {
Stack<TypeParam> s;
s.push(TypeParam{});
EXPECT_FALSE(s.empty());
s.pop();
EXPECT_TRUE(s.empty());
}
Inside these tests, access the current type using the TypeParam typedef injected by the macro expansion.
Phase 3: Register the Pattern with REGISTER_TYPED_TEST_SUITE_P
Aggregate all defined tests using REGISTER_TYPED_TEST_SUITE_P(SuiteName, TestName1, TestName2, ...). Lines 89-96 of gtest-typed-test.h implement this macro to pack the test names into an internal Templates type list and store it within a static registration structure.
// Registers the pattern (lines 89-96)
REGISTER_TYPED_TEST_SUITE_P(StackTest, IsEmpty, PushPop);
Critical constraint: This macro must appear in exactly one translation unit. Including it in multiple files causes duplicate symbol linker errors because it defines static registration objects with external linkage.
Phase 4: Instantiate with Concrete Types
Finally, instantiate the pattern using INSTANTIATE_TYPED_TEST_SUITE_P(Prefix, SuiteName, Types). Lines 106-119 utilize internal::GenerateTypeList<Types> to iterate over the type list, generate concrete test classes for each type, and register them with unique names formed by concatenating Prefix and SuiteName.
// In a .cc file (lines 106-119)
using MyTypes = ::testing::Types<int, std::string, double>;
INSTANTIATE_TYPED_TEST_SUITE_P(My, StackTest, MyTypes);
This creates test suites named My/StackTest<int>, My/StackTest<std::string>, and My/StackTest<double>, each containing the IsEmpty and PushPop tests.
Complete Working Example
Pattern Definition Header
Create a header file that declares the pattern and defines test logic without knowing the concrete types:
// stack_test_pattern.h
#include <gtest/gtest.h>
#include <stack>
template <typename T>
class StackTest : public ::testing::Test {
protected:
std::stack<T> stack_;
};
// Phase 1: Declaration
TYPED_TEST_SUITE_P(StackTest);
// Phase 2: Test definitions
TYPED_TEST_P(StackTest, DefaultConstructible) {
// TypeParam refers to the current type being tested
TypeParam val{};
this->stack_.push(val);
EXPECT_EQ(this->stack_.top(), val);
}
TYPED_TEST_P(StackTest, SizeIncreases) {
EXPECT_EQ(this->stack_.size(), 0);
this->stack_.push(TypeParam{});
EXPECT_EQ(this->stack_.size(), 1);
}
// Phase 3: Registration (must be in header if only included once, or move to .cc)
REGISTER_TYPED_TEST_SUITE_P(StackTest, DefaultConstructible, SizeIncreases);
Instantiation Translation Unit
Instantiate the pattern in a separate source file:
// test_instantiation.cc
#include "stack_test_pattern.h"
using TestTypes = ::testing::Types<int, float, std::string>;
// Phase 4: Instantiation
INSTANTIATE_TYPED_TEST_SUITE_P(Pre, StackTest, TestTypes);
Customizing Test Name Generation
GoogleTest accepts an optional fourth parameter to INSTANTIATE_TYPED_TEST_SUITE_P for custom name generation. Define a struct with a static GetName(int index) template method:
struct TypeNames {
template <typename T>
static std::string GetName(int) {
if (std::is_same<T, int>::value) return "Integer";
if (std::is_same<T, float>::value) return "Float";
return "Unknown";
}
};
INSTANTIATE_TYPED_TEST_SUITE_P(Custom, StackTest,
::testing::Types<int, float>,
TypeNames);
// Generates: Custom/StackTest_Integer/DefaultConstructible
The GTEST_NAME_GENERATOR_ machinery in gtest-typed-test.h invokes this at instantiation time to construct the final test name.
Key Implementation Files
The type-parameterized test system spans three primary headers in the GoogleTest repository:
googletest/include/gtest/gtest-typed-test.h: Contains the four public macros and their expansions (lines 59-119).googletest/include/gtest/internal/gtest-internal.h: DefinesTypeParameterizedTestand registration helpers used by the macros.googletest/include/gtest/internal/gtest-type-util.h: ProvidesGenerateTypeListand name generation utilities for type list traversal.
Because registration occurs through static object initialization (gtest_*_registered_ variables), patterns can be declared in headers and instantiated across multiple translation units without manual registry manipulation.
Summary
- Declare patterns with
TYPED_TEST_SUITE_Pto initialize the test suite state. - Define tests using
TYPED_TEST_P, accessing types viaTypeParaminside test bodies. - Register exactly once per pattern with
REGISTER_TYPED_TEST_SUITE_Pto avoid linker errors. - Instantiate across multiple translation units using
INSTANTIATE_TYPED_TEST_SUITE_Pwith a type list and optional name generator. - Reference the concrete implementation in
googletest/include/gtest/gtest-typed-test.hlines 59-119 for macro expansion details.
Frequently Asked Questions
What is the difference between TYPED_TEST and TYPED_TEST_P?
TYPED_TEST is used when the type list is known at the point of test definition, requiring TYPED_TEST_SUITE and the type list immediately. TYPED_TEST_P creates a reusable pattern where the type list is supplied later via INSTANTIATE_TYPED_TEST_SUITE_P, enabling test definitions in headers separate from instantiation sites.
Why am I getting linker errors about duplicate symbols?
REGISTER_TYPED_TEST_SUITE_P defines static objects with external linkage. If you include this macro in a header included by multiple translation units, the linker encounters duplicate definitions. Move the registration macro to a single .cc file, or ensure the header has include guards and is only processed once per pattern.
Can I instantiate the same pattern multiple times with different prefixes?
Yes. You can call INSTANTIATE_TYPED_TEST_SUITE_P multiple times with different Prefix values and different type lists. Each instantiation generates distinct test suites (e.g., Prefix1/SuiteName<int> and Prefix2/SuiteName<double>) without conflict.
How do I access the type parameter inside a TYPED_TEST_P?
The macro expansion injects a TypeParam typedef into the test class scope. Use TypeParam to declare variables, or use this to access fixture members as shown in the examples above. For qualified names, typename TestFixture::TypeParam also works within the test body.
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 →