Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 45% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 114% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 118% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 177% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 138% | 0% |
Instructions for AI coding agents on automating unit test creation using consistent software testing patterns in this C++ project.
> Ensures 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.
The FIRST principles for unit testing focus on creating effective and maintainable tests.
> Unit 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.
The In-Got-Want pattern structures each test case into three clear sections.
> 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.
Table-driven testing organizes test cases in a tabular format, allowing multiple scenarios to be defined concisely.
> 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.
Data-driven testing separates test data from test logic, enabling the same test logic to be executed with multiple sets of input 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.
The AAA pattern structures each test case into three clear phases.
> 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.
Test fixtures provide a consistent and reusable setup and teardown mechanism for test cases.
> Initialize common objects or state needed for multiple tests.
> Clean up resources or reset state after each test.
Test doubles (e.g., mocks, stubs, fakes) are simplified versions of complex objects or components used to isolate the unit under 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.
Identify new functions in src/ (e.g., src/<module>/<header>.hpp).
Create new tests colocated with source code in src/<module>/ (e.g., src/<module>/<header>_test.cpp).
Add the test file to src/<module>/CMakeLists.txt using meta_gtest() with appropriate options (e.g., WITH_DDT).
The test configuration should use ENABLE option with META_BUILD_TESTING variable:
cmake include(meta_gtest)
meta_gtest( ENABLE ${META_BUILD_TESTING} TARGET ${PROJECT_NAME}-test SOURCES <header>_test.cpp LINK ${PROJECT_NAME}::<module> )
Include comprehensive edge cases:
Structure all tests using the template pattern below.
| Command | Description | | ----------------------------------- | ----------------------------------------------------- | | make cmake-gcc-test-unit-build | CMake preset configuration and Compile with Ninja | | make cmake-gcc-test-unit-run | Execute tests via ctest | | make cmake-gcc-test-unit-coverage | Execute tests via ctest and generate coverage reports |
> Use GoogleTest (GTest) framework via #include <gtest/gtest.h>.
> Include necessary standard library headers (<vector>, <string>, <climits>, etc.) and module-specific headers in a logical order: system headers first, then project headers.
Include necessary headers in this order:
<gtest/gtest.h>, <gmock/gmock.h>)<memory>, <string>, etc.)> Use using namespace <namespace>; for convenience within test functions to reduce verbosity while maintaining clarity, since test scope is limited.
> Consolidate test cases for a single function into one TEST(...) function using table-driven testing.
This approach:
> Focus each TEST(...) function on a single function or cohesive behavior. For complex setups, use TEST_F fixtures or helper functions to reduce duplication.
> Use Google Mock (GMock) for creating test doubles (mocks, stubs, fakes) to isolate the unit under test. See the cpp-mock-testing skill.
> Employ SCOPED_TRACE(tc.label) for traceable failures in table-driven tests.
> Use EXPECT_* macros (not ASSERT_*) to allow all test cases to run.
Use these templates for new unit tests. Replace placeholders with actual values.
cpp#include <gtest/gtest.h> #include <string> #include <vector> #include "<module>/<header>.hpp" using namespace <namespace>;
cppTEST(<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>); } }
cppclass <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>); }
cppTEST(<Module>Test, <FunctionName>ThrowsOnInvalidInput) { // Arrange <Module> object; auto invalid_input = <invalid_value>; // Act & Assert EXPECT_THROW(object.<function>(invalid_input), <ExceptionType>); }
cppTEST(<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); } }
cpp#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); } }
Other measured skills in the registry, with their headline benchmark lift.