mirror of
https://github.com/github/awesome-copilot.git
synced 2026-05-29 18:11:45 +00:00
7.5 KiB
7.5 KiB
applyTo, description
| applyTo | description |
|---|---|
| ** | Comprehensive QA engineering best practices covering test strategy, test pyramid, naming conventions, assertion patterns, bug reporting, and automation guidelines for modern software projects. |
QA Engineering Best Practices
A structured set of instructions for GitHub Copilot to assist with quality assurance engineering tasks including test design, automation, and defect management across any technology stack.
Core Testing Principles
- Test early, test often: Shift testing left — write tests alongside code, not after.
- Test one thing at a time: Each test case should verify a single behaviour or assertion.
- Tests are first-class code: Apply the same readability, naming, and refactoring standards to test code as to production code.
- Fail fast: Tests should produce clear, actionable failures that point directly to the broken behaviour.
- Deterministic tests: Tests must produce the same result on every run. Eliminate randomness, timing dependencies, and shared mutable state.
- Independent tests: No test should depend on another test's side effects. Tests must be runnable in any order.
Test Pyramid
Follow the test pyramid to balance coverage, speed, and maintenance cost:
| Layer | Scope | Quantity | Speed |
|---|---|---|---|
| Unit | Single function / class | Many (60–70 %) | Milliseconds |
| Integration | Module boundaries, DB, API contracts | Moderate (20–30 %) | Seconds |
| End-to-End | Full user journey across UI + backend | Few (5–10 %) | Minutes |
- Prefer unit tests for business logic and edge cases.
- Use integration tests to validate contracts between services and external dependencies.
- Reserve end-to-end tests for critical user paths and smoke suites.
Test Naming Conventions
Use the Given / When / Then (GWT) or should_doX_whenY pattern consistently.
// Good – describes scenario, action, expected result
test('should return 404 when product id does not exist')
test('given an expired token, when the user calls /me, then it returns 401')
// Bad – vague, implementation-focused
test('test1')
test('check user')
- Group related tests in
describe/contextblocks named after the unit under test. - Use
itortestfor individual cases. - Test names must be readable as standalone sentences.
Assertion Best Practices
- One logical assertion per test where practical; avoid asserting multiple unrelated things.
- Use specific matchers over equality checks (
toContain,toBeGreaterThan,toMatchObject). - Always assert the exact expected value, not just truthiness (
expect(result).toBe(42)notexpect(result).toBeTruthy()). - For exception testing, assert both the exception type and message.
- Prefer positive assertions over negative ones when testing the happy path.
// Good
expect(response.status).toBe(200);
expect(response.body.items).toHaveLength(3);
// Avoid
expect(response).toBeTruthy();
expect(response.body).not.toBeNull();
Test Data Management
- Use factories or builders to create test data — avoid hardcoding raw objects in every test.
- Keep test data minimal: only include fields relevant to the test.
- Use unique identifiers per test run to avoid collision in shared environments.
- Never use production data or PII in tests.
- Reset or isolate state between tests (in-memory DB, transactions rolled back, mocked dependencies).
Mocking and Stubbing Guidelines
- Mock at the boundary (HTTP clients, DB adapters, message queues) — not deep inside business logic.
- Prefer real implementations for pure functions and simple value objects.
- Stubs return controlled data; mocks additionally verify interactions — choose the right tool.
- Reset all mocks between tests to prevent state leakage.
- Document why a dependency is mocked if the reason is non-obvious.
API Testing
- Validate status code, response schema, headers, and response time for every endpoint.
- Test all HTTP methods the endpoint exposes (GET, POST, PUT, PATCH, DELETE).
- Cover authentication and authorisation paths: valid token, expired token, missing token, wrong role.
- Test boundary values for inputs: empty string, null, max length, special characters, Unicode.
- Validate error response bodies follow a consistent schema.
- Assert idempotency for PUT and DELETE operations.
UI / End-to-End Testing
- Target user-visible behaviour, not implementation details (avoid asserting CSS classes or internal state).
- Use accessible selectors in order of preference:
role→label→test-id→text. - Avoid
sleep/ fixed waits; use explicit waits on element state (visible, enabled, network idle). - Run E2E tests against a stable, isolated environment (not shared staging).
- Keep E2E scenarios short and focused — break long flows into smaller composable steps.
- Capture screenshots and traces on failure for easier debugging.
Performance Testing
- Define SLOs (Service Level Objectives) before writing performance tests: target latency p50/p95/p99, throughput, error rate.
- Include ramp-up, steady state, and ramp-down phases in load tests.
- Test under realistic data volumes — synthetic tests with empty DBs are not representative.
- Track results over time to detect performance regressions.
- Distinguish between load testing (expected traffic), stress testing (beyond capacity), and soak testing (sustained load over time).
Bug Reporting Standards
A good bug report includes:
- Title: concise, specific — include component, action, and symptom (
[Checkout] Order total is incorrect when coupon is applied). - Environment: OS, browser/runtime version, deployment environment.
- Steps to reproduce: numbered, minimal, deterministic.
- Expected result: what should happen.
- Actual result: what actually happens, including error messages and stack traces.
- Severity: Critical / High / Medium / Low (defined by business impact).
- Attachments: screenshots, logs, network traces, test IDs.
Test Coverage Guidelines
- Aim for meaningful coverage, not a percentage target — 100 % line coverage with trivial tests is worthless.
- Prioritise coverage for critical paths, complex logic, and previously buggy areas.
- Track branch coverage and mutation scores alongside line coverage.
- Use coverage reports to find untested edge cases, not to game metrics.
CI/CD Integration
- Tests must pass in CI before any merge to main/trunk — no exceptions.
- Run fast tests (unit, lint) on every commit; run slow tests (integration, E2E) on PR merge or nightly.
- Make test failures visible and actionable in CI output — include test name, failure reason, and relevant logs.
- Archive test reports and artefacts (JUnit XML, coverage HTML, traces) as CI build artefacts.
- Configure flaky test detection: auto-retry once, flag as flaky after repeated inconsistency.
Test Review Checklist
Before approving a PR that changes tests:
- New behaviour is covered by tests at the appropriate pyramid level.
- Tests are named clearly and follow the project convention.
- No
sleep,Thread.Sleep, or arbitrary timeouts. - Mocks are reset after each test.
- No hardcoded environment-specific values (URLs, credentials).
- Tests are independent and can run in isolation.
- Test code is readable without needing to read the implementation.