--- name: testcase-common-setup description: '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.' user-invocable: 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`: ```cpp class : public ::testing::Test { protected: // Shared state goes here — typically the System Under Test ; }; ``` - Place it right after the includes, before the first test - Declare shared variables as `protected` members - 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: ```cpp class : public ::testing::Test { protected: ; void SetUp() override { // Lines that every test needs — extracted here once ; ; } }; ``` 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: ```cpp // Before TEST(, ) { ; // ← now redundant ; // ← now redundant (in SetUp) ... } // After TEST_F(, ) { // 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: ```bash ./run_tests.sh ``` All tests must pass before considering the refactor complete. ## Example Before — three tests with duplicated setup: ```cpp 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()`: ```cpp 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); } ``` ## References - [Google Test: Test Fixtures](https://google.github.io/googletest/primer.html#same-data-multiple-tests)