Test-related code must follow the specifications below.
Before Coding
First list the public interfaces, key behaviors, and boundary conditions of the module under test, design test cases, and then write test code.
TDD Process (Mandatory)
New features and bug fixes must follow the red-green-refactor cycle:
- Red — Write a test describing the expected behavior, run it and confirm it fails
- Green — Write the minimum code to make the test pass
- Refactor — Clean up the code while keeping tests passing
If the test passes immediately after being written, it means the test did not verify new behavior—re-examine the test. You must proceed in vertical slices: one behavior → one failing test → minimal implementation → after it passes, move on to the next behavior. It is forbidden to write all tests in a batch first and then write the implementation in a batch.
Exempt Scenarios (just mark [-] and explain the reason):
- Pure UI style adjustments (no logic changes)
- Configuration file modifications
- Documentation/comment changes
- Rapid prototyping exploration (explicitly requested by the user)
Except for exempt scenarios, no tests written first = no implementation code may be written.
Coverage Strategy
- Core business logic: unit tests must cover it
- API endpoints: integration tests cover the main paths (success + main failure scenarios)
- Key user flows: E2E tests cover them
- Bug fixes: write a failing test first, then fix it (red-green verification)
Writing Tests
- Tests verify externally observable behavior through public interfaces, not private functions, internal call order, or implementation shape
- Test names describe behavior:
should reject expired tokens, nottest token - AAA pattern: Arrange → Act → Assert
- Each test is independent and does not depend on execution order
- Mock external dependencies (database/API/file system), not the code under test itself; if internal collaborators must be mocked, first assess whether the interface is too shallow or the test entry point is wrong
Boundary Cases (Must Cover)
- Empty values: null / undefined / empty string / empty array
- Boundary values: 0, -1, MAX_INT, overly long strings
- Error paths: invalid input, network timeout, insufficient permissions
- Concurrency: race conditions (if applicable)
Test Quality
- Avoid fragile tests: do not depend on time, random numbers, or external services
- Use factory/fixture for test data, do not hardcode
- Assert specific values, not just that something "is not empty"
- One test verifies one behavior
- Good tests should withstand internal refactoring; if renaming an internal function causes tests to fail, it means the tests are coupled to the implementation
Delivery Checklist
- Tests cover public interfaces and external behavior, and do not lock in implementation details
- Core logic has unit tests
- Test names describe behavior
- Main boundary cases are covered
- Tests can run independently