161 lines
4.2 KiB
Markdown
161 lines
4.2 KiB
Markdown
---
|
|
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 <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 `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 <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:
|
|
|
|
```cpp
|
|
// 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:
|
|
|
|
```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) |