Loading...
Loading...
Automates unit test creation for C++ projects using GoogleTest (GTest) framework with consistent software testing patterns including In-Got-Want, Table-Driven Testing, and AAA patterns. Use when creating, modifying, or reviewing unit tests, or when the user mentions unit tests, test coverage, or GTest.
npx skill4agent add sentenz/skills cpp-unit-testingEnsures high code quality and reliability. Tests are self-documenting, reducing cognitive load for reviewers and maintainers.
Uniform structure across tests ensures predictable, familiar code that team members can navigate efficiently.
Table-driven and data-driven approaches minimize boilerplate code when adding new test cases, making it simple to expand coverage.
Scoped traces and detailed assertion messages pinpoint failures quickly during continuous integration and local testing.
FIRSTUnit tests should execute quickly to provide rapid feedback during development and continuous integration.
Each unit test should be self-contained and not rely on the state or behavior of other tests.
Unit tests should produce deterministic results every time they are run, regardless of the environment or order of execution.
Unit tests should have clear pass/fail outcomes without requiring manual inspection.
Unit tests should be written and executed early in the development process to catch issues as soon as possible.
Defines the input parameters or conditions for the test.
Captures the actual output or result produced by the code under test.
Specifies the expected output or result that the test is verifying against.
Each row in the table represents a distinct test case with its own set of inputs and expected outputs.
The test framework iterates over each row, executing the same test logic with different data.
Test data can be stored in external files (e.g., JSON, CSV) and loaded at runtime.
The same test logic can be reused with different datasets, enhancing maintainability and coverage.
Set up the necessary preconditions and inputs for the test.
Execute the function or method being tested.
Verify that the actual output matches the expected output.
Initialize common objects or state needed for multiple tests.
Clean up resources or reset state after each test.
Simulate the behavior of real objects and verify interactions.
Provide predefined responses to method calls without implementing full behavior.
Implement simplified versions of real objects with limited functionality.
src/src/<module>/<header>.hppsrc/<module>/src/<module>/<header>_test.cppsrc/<module>/CMakeLists.txtmeta_gtest()WITH_DDTENABLEMETA_BUILD_TESTINGinclude(meta_gtest)
meta_gtest(
ENABLE ${META_BUILD_TESTING}
TARGET ${PROJECT_NAME}-test
SOURCES
<header>_test.cpp
LINK
${PROJECT_NAME}::<module>
)| Command | Description |
|---|---|
| CMake preset configuration and Compile with Ninja |
| Execute tests via ctest |
| Execute tests via ctest and generate coverage reports |
Use GoogleTest (GTest) framework via.#include <gtest/gtest.h>
Include necessary standard library headers (,<vector>,<string>, etc.) and module-specific headers in a logical order: system headers first, then project headers.<climits>
<gtest/gtest.h><gmock/gmock.h><memory><string>Usefor convenience within test functions to reduce verbosity while maintaining clarity, since test scope is limited.using namespace <namespace>;
Consolidate test cases for a single function into onefunction using table-driven testing.TEST(...)
Focus eachfunction on a single function or cohesive behavior. For complex setups, useTEST(...)fixtures or helper functions to reduce duplication.TEST_F
Use Google Mock (GMock) for creating test doubles (mocks, stubs, fakes) to isolate the unit under test. See the cpp-mock-testing skill.
Employfor traceable failures in table-driven tests.SCOPED_TRACE(tc.label)
Usemacros (notEXPECT_*) to allow all test cases to run.ASSERT_*
#include <gtest/gtest.h>
#include <string>
#include <vector>
#include "<module>/<header>.hpp"
using namespace <namespace>;TEST(<Module>Test, <FunctionName>)
{
// In-Got-Want
struct Tests
{
std::string label;
struct In
{
/* input types and names */
} in;
struct Want
{
/* expected output type(s) and name(s) */
} want;
};
// Table-Driven Testing
const std::vector<Tests> tests = {
{"case-description-1", {/* input */}, {/* expected */}},
{"case-description-2", {/* input */}, {/* expected */}},
};
for (const auto &tc : tests)
{
SCOPED_TRACE(tc.label);
// Arrange
<Module> <object>;
// Act
auto got = <object>.<function>(tc.in.<input>);
// Assert
EXPECT_EQ(got, tc.want.<expected>);
}
}class <Module>Test : public ::testing::Test
{
protected:
void SetUp() override
{
// Initialize common objects or state
}
void TearDown() override
{
// Clean up resources or reset state
}
<Module> object_;
};
TEST_F(<Module>Test, <FunctionName>)
{
// Arrange
auto input = <input_value>;
// Act
auto got = object_.<function>(input);
// Assert
EXPECT_EQ(got, <expected>);
}TEST(<Module>Test, <FunctionName>ThrowsOnInvalidInput)
{
// Arrange
<Module> object;
auto invalid_input = <invalid_value>;
// Act & Assert
EXPECT_THROW(object.<function>(invalid_input), <ExceptionType>);
}TEST(<Module>Test, <FunctionName>BoundaryValues)
{
// In-Got-Want
struct Tests
{
std::string label;
struct In
{
<input_type> input;
} in;
struct Want
{
<output_type> expected;
} want;
};
// Table-Driven Testing with boundary cases
const std::vector<Tests> tests = {
{"minimum-value", {<MIN_VALUE>}, {/* expected */}},
{"maximum-value", {<MAX_VALUE>}, {/* expected */}},
{"zero-value", {0}, {/* expected */}},
{"empty-input", {{}}, {/* expected */}},
{"negative-value", {-1}, {/* expected */}},
};
for (const auto &tc : tests)
{
SCOPED_TRACE(tc.label);
// Arrange
<Module> object;
// Act
auto got = object.<function>(tc.in.input);
// Assert
EXPECT_EQ(got, tc.want.expected);
}
}#include <nlohmann/json.hpp>
#include <fstream>
TEST(<Module>Test, <FunctionName>DataDriven)
{
// Load test data from JSON file
std::ifstream file("<module>/<header>_test.json");
nlohmann::json test_data;
file >> test_data;
for (const auto &tc : test_data["tests"])
{
SCOPED_TRACE(tc["label"].get<std::string>());
// Arrange
<Module> object;
auto input = tc["in"]["input"].get<<input_type>>();
auto expected = tc["want"]["expected"].get<<output_type>>();
// Act
auto got = object.<function>(input);
// Assert
EXPECT_EQ(got, expected);
}
}