4.2 KiB
4.2 KiB
name, description, user-invocable
| name | description | user-invocable |
|---|---|---|
| testcase-common-setup | Use when: refactoring tests to eliminate duplication via test fixtures, extracting common setup into SetUp(), converting TEST() to TEST_F() in Google Test. Run this after adding new test cases that duplicate setup code. | true |
Test Case Common Setup (Google Test)
This skill refactors Google Test suites by extracting duplicate setup code into a shared test fixture with SetUp(). Applying this skill makes tests more maintainable and reduces noise from repeated scaffolding.
When to Use
- Multiple
TEST()cases create the same object or call the same configuration - A new test case requires copying setup lines from an existing test
- Reviewing test code and noticing the same 2+ lines repeated across every test
- After adding a new test that duplicates setup from existing tests
Procedure
1. Identify Duplicated Setup
Scan all TEST() blocks in the test suite. Look for lines that are identical across every test — typically:
- Object creation:
VendingMachine vm;(or similar SUT construction) - Common configuration calls:
vm.configureSlot(...) - Pre-conditions that apply to all tests
2. Create a Test Fixture
Introduce a fixture class deriving from ::testing::Test:
class <TestSuiteName> : public ::testing::Test {
protected:
// Shared state goes here — typically the System Under Test
<Type> <variable>;
};
- Place it right after the includes, before the first test
- Declare shared variables as
protectedmembers - Name the fixture after the test suite (e.g.
VendingMachineTest)
3. Extract Shared Setup into SetUp()
Define void SetUp() override inside the fixture with the lines common to all tests:
class <TestSuiteName> : public ::testing::Test {
protected:
<Type> <variable>;
void SetUp() override
{
// Lines that every test needs — extracted here once
<sharedSetupLine1>;
<sharedSetupLine2>;
}
};
Rules:
- Only move lines that appear in every test
- If a line only appears in some tests, leave it in the individual
TEST_F()bodies - Keep
SetUp()focused — it runs before each test, so don't put expensive or test-specific logic there
4. Convert TEST() to TEST_F()
Replace every occurrence:
// Before
TEST(<TestSuiteName>, <TestCaseName>)
{
<Type> <variable>; // ← now redundant
<sharedSetupLine1>; // ← now redundant (in SetUp)
...
}
// After
TEST_F(<TestSuiteName>, <TestCaseName>)
{
// Only test-specific code remains
...
}
- Remove the redundant object declaration from each test body
- Remove any lines now handled by
SetUp() - Remove configuration calls that were duplicates across all tests
5. Verify
Run the test suite to confirm all tests still pass:
./run_tests.sh
All tests must pass before considering the refactor complete.
Example
Before — three tests with duplicated setup:
TEST(VendingMachineTest, unconfigured_choice_dispenses_nothing)
{
VendingMachine vm;
EXPECT_EQ(vm.dispense(Choice::Cola), std::nullopt);
}
TEST(VendingMachineTest, configured_slot_dispenses_can)
{
VendingMachine vm;
vm.configureSlot(Choice::Cola, Can::Coke);
EXPECT_EQ(vm.dispense(Choice::Cola), Can::Coke);
}
TEST(VendingMachineTest, multiple_slots_dispense_correctly)
{
VendingMachine vm;
vm.configureSlot(Choice::FizzyOrange, Can::Fanta);
vm.configureSlot(Choice::Cola, Can::Coke);
EXPECT_EQ(vm.dispense(Choice::FizzyOrange), Can::Fanta);
}
After — fixture with SetUp():
class VendingMachineTest : public ::testing::Test {
protected:
VendingMachine vm;
void SetUp() override
{
vm.configureSlot(Choice::Cola, Can::Coke);
vm.configureSlot(Choice::FizzyOrange, Can::Fanta);
}
};
TEST_F(VendingMachineTest, unconfigured_choice_dispenses_nothing)
{
EXPECT_EQ(vm.dispense(Choice::Beer), std::nullopt);
}
TEST_F(VendingMachineTest, configured_slot_dispenses_can)
{
EXPECT_EQ(vm.dispense(Choice::Cola), Can::Coke);
}
TEST_F(VendingMachineTest, multiple_slots_dispense_correctly)
{
EXPECT_EQ(vm.dispense(Choice::FizzyOrange), Can::Fanta);
}