SKILL.md
Test Planning Process
Quick Reference
| Dimension | Rule |
|---|---|
| Test Boundary | Test at the highest boundary that directly expresses the feature's business goal (e.g. integration/request vs unit) |
| Coverage Goal | Cover all primary paths, all input boundary values, and all expected error flows |
| First Failing Test | Select the single simplest assertion that will fail on the current code and prove the feature is missing |
| Isolation | Isolate tests from external networks, dates, and shared database states |
HARD-GATE
TEST PLANNING GATES:
1. DO NOT write test cases without defining a test plan first.
2. ALWAYS start testing at the most relevant boundary (don't write 10 unit tests for a feature that needs a request test, and vice versa).
3. The first failing test MUST be identified explicitly in the plan before writing it.
4. All test data must be synthetic; never use real production values or API payloads in test plans.
Process Steps
Step 1: Determine the Test Boundary
Identify where the behavior is observed:
- Request / API Boundary: Use when verifying HTTP statuses, headers, query parsing, or JSON payload structures.
- Service / Business Boundary: Use when validating domain invariants, complex calculations, or coordination between objects.
- Unit Boundary: Use when verifying low-level calculations, state changes on a single object, or formatting logic.
Step 2: List the Test Cases
For the selected boundary, map out the test matrix:
- Happy Paths: Standard expected execution flows.
- Boundary Values: Zero, nil, empty strings, maximum lengths, negative values.
- Error Paths: Invalid inputs, database failures, external service timeouts, auth failures.
Step 3: Select the First Failing Test
- Choose the single simplest test case from the matrix that is expected to fail on the current code.
- This serves as the initial "Red" state to kick off the TDD loop.
Step 4: Plan Test Isolation
- Identify any external dependencies (network APIs, system clocks, file systems).
- Plan mocks, stubs, or test doubles to isolate the tests and prevent flaky failures.
Checkpoint Pattern
Align with the user:
- Test Plan Proposal: Present the target boundary, the list of happy/edge/error cases, and specify which test will be the first failing test.
- Handoff: Present the skeleton code for the first failing test before writing any implementation.
Inline Example
Feature: POST /users — create a new user account
Selected Boundary: Request / API (verifies HTTP status and JSON response shape)
| # | Type | Description | Expected Result | First Failing? |
|---|---|---|---|---|
| 1 | Happy path | Valid email + password | 201 Created, body contains id |
✅ Yes |
| 2 | Boundary | Password at minimum length (8 chars) | 201 Created |
|
| 3 | Error | Missing email field | 422 Unprocessable Entity |
|
| 4 | Error | Duplicate email already in database | 409 Conflict |
First Failing Test — skeleton (Python / pytest + requests):
def test_create_user_returns_201_with_id(client):
payload = {"email": "[email protected]", "password": "s3cr3t!X"}
response = client.post("/users", json=payload)
assert response.status_code == 201
assert "id" in response.json()
First Failing Test — skeleton (JavaScript / Jest + supertest):
test('POST /users returns 201 with id for valid payload', async () => {
const res = await request(app)
.post('/users')
.send({ email: '[email protected]', password: 's3cr3t!X' });
expect(res.status).toBe(201);
expect(res.body).toHaveProperty('id');
});
Run the skeleton as-is — it should fail (Red). Proceed to tdd-process to make it pass.
Anti-Patterns
- Coverage Blindness: Happy-path-only tests with no error/edge cases.
- Low-Value Testing: Hundreds of unit tests for trivial methods with zero integration coverage.
- Shared State Leaks: Tests that write to a shared database or file without cleanup.
Integration
| Context | Next Skill |
|---|---|
| Writing the failing test | tdd-process |
| General design modeling | model-domain |