Skip to content

Commit 07db966

Browse files
committed
Add and improve the 'General testing principles' section
1 parent 36a29b0 commit 07db966

File tree

1 file changed

+100
-11
lines changed

1 file changed

+100
-11
lines changed

practices/testing.md

Lines changed: 100 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,120 @@
2323

2424
## General testing principles
2525

26+
- **Design for testability**, and [shift testing left and right](https://www.redhat.com/en/topics/devops/shift-left-vs-shift-right)
27+
28+
Testing is most effective when it is baked into the system design and runs across the entire lifecycle-from development to production. Teams should build systems that are inherently testable and support both early validation ("shift left") and ongoing validation in live environments ("shift right"). Key Practices:
29+
30+
- Shift left, aka test early
31+
- Testing starts at the design and coding phase, not after.
32+
- Pre-commit hooks, linting, static code analysis, and unit tests run locally before code even hits a branch.
33+
- [Test-Driven Development (TDD)](https://www.thoughtworks.com/en-gb/insights/blog/test-driven-development-best-thing-has-happened-software-design) and [Behavior-Driven Development (BDD)](https://www.thoughtworks.com/en-gb/insights/blog/applying-bdd-acceptance-criteria-user-stories) encourage writing tests before or alongside code, ensuring clarity of requirements and better design.
34+
- Test planning is informed by risk analysis and [architectural decisions](../any-decision-record-template.md) made early on.
35+
- Design for testability
36+
- Systems are designed with observability, modularity, and controllability in mind.
37+
- Expose clear APIs, provide injection points for test doubles (mocks/stubs), and avoid tight coupling.
38+
- Feature toggles and dependency injection help test components in isolation without complex setups.
39+
- Make non-functional testing (performance, security, resilience) a first-class concern, with hooks and controls to simulate adverse conditions.
40+
- Design for reproducibility
41+
- Tests should be idempotent and easily repeatable in any environment (local, test, staging, production).
42+
- Shift right, aka test in production
43+
- Testing does not stop at deployment-continuous validation in production is essential.
44+
- Implement real-time monitoring, synthetic checks, health probes, and user behavior tracking.
45+
- Use canary deployments, blue-green releases, and feature flags to roll out changes gradually, monitoring for issues as they surface.
46+
- Employ chaos engineering to test system resilience under real-world failure conditions.
47+
- Instrument systems to detect anomalies, performance degradation, or unexpected behaviors automatically.
48+
49+
In a high-throughput environment-where deploying at least once a day is the norm, adhering to the design for testability principle is paramount. The benefits include: 1) *faster feedback loops* – early testing catches issues when they are cheapest to fix, while testing later in the cycle ensures real-world readiness; 2) *increased confidence* – testing at all stages validates assumptions, improves system reliability, and supports safe, frequent releases; and 3) *higher quality by design* – systems built for testability are easier to maintain, scale, and evolve.
50+
2651
- **Quality is the whole team's responsibility**
2752
- Education on testing and testing principles should be important to the whole team.
2853
- Quality approaches should be driven as a team and implemented by everyone.
2954
- Teams should consider running regular coaching / mentoring sessions to support colleagues who are less experienced in testing to grow their skills, for example by no-blame group discussions to identify edge-case tests which have so far been missed, tests positioned incorrectly in the [test pyramid](https://martinfowler.com/articles/practical-test-pyramid.html), and pairing with a tester navigating so that the driver learns the necessary skills.
55+
- Testing is a shared team concern, not a tester’s job alone. Developers own testing for their code, including pipeline tests, monitoring their deploys, infrastructure and on-call responsibilities, as deploying at least once a day requires autonomy and accountability.
3056

3157
- **Combining business knowledge with testing knowledge yields better quality outcomes**
32-
- Include business knowledge and critical thinking as part of assurance
33-
- Intrinsic knowledge and mindset of the team is key to driving quality outcomes
58+
- Include business knowledge and critical thinking as part of technical assurance.
59+
- Intrinsic knowledge and mindset of the team is key to driving quality outcomes.
3460

3561
- **Testing is prioritised based on risk**
36-
- A testing risk profile is defined and understood by the whole team, including the customer
37-
- Risk appetite should be worked across the whole team, including customers and/or users
38-
- Solution Assurance risks and Clinical Safety hazards must also be considered when prioritising risks
62+
- A testing risk profile is defined and understood by the whole team, including the customer.
63+
- Risk appetite should be worked across the whole team, including customers and/or users.
64+
- Assurance risks and Clinical Safety hazards must also be considered when prioritising risks.
3965

4066
- **Testing is context driven**
4167
- Context should be considered when deciding on test techniques and tools to use.
4268

69+
- **Test data management is a first-class citizen**
70+
71+
Frequent deployments require reliable and consistent test environments. Data drift or stale data can undermine test confidence.
72+
73+
- Test data should be easy to generate, isolate and reset.
74+
- Use factories, fixtures or synthetic data generation.
75+
- Anonymised production data can improve test relevance, especially in performance or exploratory testing.
76+
77+
- **Consistent, CLI-driven test execution across all environments**
78+
79+
Tests and test processes should execute consistently in every environment, ranging from local developer workstations to cloud-based CI/CD pipelines. Using a CLI-driven approach ensures standardisation, portability and reliability.
80+
81+
- Command-Line interface (CLI) as the default test runner
82+
- All tests (unit, integration, functional, performance) must be executable through straightforward, repeatable CLI commands.
83+
- Ensure a single, consistent command can run the complete test suite, facilitating rapid local and remote execution , e.g. `make test`
84+
- Consistent environment configuration
85+
- Clearly defined and documented dependencies (IaC) ensure that test environments are reproducible, reducing "it works on my machine" scenarios.
86+
- Use Infrastructure as Code (IaC) or containerised test environments (e.g. Docker) to guarantee identical configurations between local machines and cloud pipelines.
87+
- Reproducibility and portability
88+
- Tests must behave identically when run locally and remotely. No tests should rely on hidden state, manual configuration, or proprietary local tooling.
89+
- Standardise environment configuration through version-controlled configuration files or scripts, enabling teams to replicate exact test runs on any workstation or CI/CD environment effortlessly.
90+
- Dependency isolation and management
91+
- Dependencies should be explicitly declared and managed using tools appropriate to your technology stack (e.g. Python’s requirements.txt, Node’s package.json, etc.).
92+
- Employ dependency management tools (e.g. virtual environments, containers, package managers) to enforce consistency.
93+
- Environment parity between development and production
94+
- Aim to eliminate differences between local, staging and production environments. Running tests consistently across environments ensures that deployment to production is predictable and low-risk.
95+
- Teams regularly validate environment parity through automated checks or smoke tests.
96+
- Clear and consistent documentation
97+
- Standardised CLI test commands and environment setups must be clearly documented (e.g. README.md) and version-controlled.
98+
- Onboarding documentation should guide new developers to execute the same tests consistently across their local and cloud environments.
99+
100+
- **Validate continuously through observability**
101+
102+
Effective testing does not stop once software reaches production. By integrating observability into testing, teams gain real-time insights and continuously validate system behavior under real-world conditions. Observability-driven testing means using telemetry data, such as metrics, logs, tracing and user analytics, to shape test approach, validate assumptions, detect regressions early and drive continuous improvement.
103+
104+
- Instrument systems for visibility
105+
- Implement consistent instrumentation (metrics, logs, tracing) across services to capture detailed runtime behavior.
106+
- Ensure telemetry data clearly maps back to business functionality, enabling both technical and business stakeholders to interpret the data.
107+
- Continuous monitoring in production
108+
- Use dashboards and automated alerts to monitor system health continuously, proactively detecting anomalies, performance degradation or unexpected behaviors.
109+
- Regularly verify production health checks and synthetic monitoring results as part of your ongoing testing activities.
110+
- Real-user monitoring (RUM)
111+
- Observe and analyze how real users interact with the system, capturing actual usage patterns, performance characteristics and edge-case scenarios.
112+
- Leverage this data to refine existing automated tests or identify new scenarios worth automating.
113+
- Distributed tracing to inform testing
114+
- Use distributed tracing data (such as OpenTelemetry, AWS X-Ray or Azure Monitor Application Insights) to understand how requests flow through services, identify latency hotspots and pinpoint complex dependency issues.
115+
- Translate tracing insights into targeted integration tests and service-level tests, improving test precision.
116+
- Alerting and proactive issue detection
117+
- Set clear, actionable alerts based on predefined thresholds that matter to users and the business.
118+
- Tie production alerts back into automated test scenarios, ensuring tests reflect actual production conditions and preventing similar issues from recurring.
119+
- Feedback loops into test planning
120+
- Regularly analyze observability data (logs, metrics, user sessions) during sprint planning or retrospectives to identify gaps in testing coverage.
121+
- Treat production incidents as opportunities for testing improvements, each incident should trigger analysis of whether similar risks are sufficiently covered by automated or exploratory tests.
122+
- Testing resilience and failure modes
123+
- Observability supports chaos engineering practices by providing detailed visibility into system behavior under fault conditions.
124+
- Proactively test recovery procedures, failovers and resilience strategies based on observed patterns of failure or degradation from production data.
125+
126+
Applying this principle reduces mean-time-to-detection and recovery, improving reliability, enables teams to validate assumptions using real data rather than guesswork, enhances the quality of future releases by continuously learning from real-world usage patterns. Increases confidence when releasing frequently, knowing production issues can be quickly identified, understood and addressed.
127+
43128
- **Testing is assisted by automation**
44-
- Appreciate that not everything can be automated
45-
- Identify good candidates for automation - particular focus on high risk and repeatable areas
46-
- Automated tests should be used to provide confidence to all stakeholders. This includes test analysts themselves who should be familiar with what the tests are doing to allow them to make decisions on what they want to test.
129+
130+
Test automation is critical for maintaining rapid, frequent deployments while consistently ensuring quality. It provides scalable confidence in software changes, reduces repetitive manual efforts, and frees up human activities for high-value exploratory testing. Automated testing should be seen as a core enabler of development workflow, particularly when combined with a robust approach to design for testability.
131+
132+
- Appreciate that not everything can be automated, however automated testing, supported by intentional design for testability, increases delivery speed, confidence and adaptability.
133+
- Identify good candidates for automation - particular focus on high risk and repeatable areas.
134+
- Automated tests should be used to provide confidence to all stakeholders. This includes test analysts themselves who should be familiar with what the tests are doing to allow them to make decisions on what they want to test.
135+
- It defines clear, technology-neutral contracts and behaviors. This provides stable reference points when migrating or re-implementing systems in new languages or platforms. Automated contract tests (e.g. consumer-driven contract tests) enable safe technology swaps, helping confirm system compatibility across evolving stacks.
47136
- Automated test packs should be maintained regularly to ensure they have suitable coverage, are efficient and providing correct results.
48-
- Consider using testing tools to enhance other test techniques.
49-
- Eg. using record and play tools to aid exploratory UI testing
50-
- Eg. using API testing tools to aid exploratory API testing
137+
- Consider using testing tools to enhance other test techniques, e.g.
138+
- using record and play tools to aid exploratory UI testing,
139+
- using API testing tools to aid exploratory API testing.
51140

52141
- **Testing should be continually improved**
53142
- [Peer reviews](../patterns/everything-as-code.md#code-review) must consider tests as a first-class concern - this includes tests that are present / have been added (e.g. whether they are positioned appropriately in the [test pyramid](https://martinfowler.com/articles/practical-test-pyramid.html), whether they are triggered appropriately in CI builds, etc) and any tests that are missing, e.g. edge-cases not yet considered

0 commit comments

Comments
 (0)