Instruction file imported from sanjyotagureddy/x-lynkly (
.github/instructions/test.instructions.md). Copyright stays with the author.
Test Instructions
These instructions apply to all test code under tests/** in this repository.
Testing Goals
- Validate behavior, not implementation details.
- Keep tests deterministic, isolated, and readable.
- Cover happy paths, failure paths, and edge cases.
- Protect the architecture by testing boundaries, contracts, and integration points.
- Keep code coverage at a minimum of 80% for the repository, with higher coverage expected for core domain and critical application slices.
Required Test Strategy
Use the right test level for the change:
- Unit tests for pure domain and application logic.
- Integration tests for EF Core, Redis, messaging, and API boundaries.
- Architecture tests for dependency direction and layer boundaries.
- Contract tests when external APIs or message contracts are involved.
- Performance tests for hot-path redirects, latency, and throughput-sensitive code.
Best Practices
- Prefer Arrange-Act-Assert structure where it keeps tests clear.
- Give tests names that describe behavior and expectation.
- Keep one reason to fail per test when practical.
- Use fixed clocks, seeded data, and controlled inputs.
- Avoid shared mutable state between tests.
- Prefer test doubles at boundaries; do not mock internals unnecessarily.
- Prefer integration coverage over over-mocking persistence or messaging layers.
- Test the public behavior of a slice end to end when the slice is small enough to do so cleanly.
- Keep test helpers simple, reusable, and local to the test project unless truly shared.
Coverage Rules
- Maintain at least 80% overall code coverage.
- Aim for 100% coverage on critical domain logic and high-value application slices.
- Do not use coverage as a substitute for meaningful assertions.
- Exclude generated code, trivial boilerplate, and framework bootstrap only when the repo's tooling explicitly permits it.
- If a change lowers coverage, add tests in the same change unless explicitly out of scope.
Messaging and Resilience Tests
- Verify retry behavior for transient failures.
- Verify poison-message handling and DLQ routing.
- Verify idempotency for duplicate deliveries.
- Verify event publication does not block critical request paths.
- Use broker-agnostic assertions where possible so RabbitMQ can be replaced later without rewriting the test intent.
Persistence Tests
- Validate EF Core mappings, query behavior, and migration safety.
- Prefer real database-backed integration tests for persistence behavior.
- Verify schema changes with migrations rather than ad-hoc setup.
- Assert transaction boundaries and data consistency where relevant.
API Tests
- Verify request validation, status codes, and response contracts.
- Keep endpoint tests thin and focused on transport behavior.
- Ensure routes remain versioned and predictable.
- Test failure responses as deliberately as success responses.
What to Avoid
- Avoid flaky timing-based tests.
- Avoid tests that depend on external networks or paid services.
- Avoid asserting implementation details that make refactoring difficult.
- Avoid large, opaque test setups that hide the behavior under test.
- Avoid lowering the coverage floor unless the change is explicitly a test-exception review.
Completion Checklist
- Tests for the changed behavior are added or updated.
- Relevant test types are chosen correctly for the change.
- The coverage floor is preserved at 80% or better.
- The test suite remains deterministic and maintainable.
- Any new failure paths introduced by the change are covered.