How to build a test strategy from risks

With your risks ranked by exposure, the next question is how to actually address them: which testing types, at which levels, using which techniques, and with what coverage targets. This is where the portfolio gets built, and it's the most detailed part of the process, because the testing landscape is large and the decisions compound.

Most teams I've seen choose and run testing activities without a risk map: "we need more integration tests", "let's add load testing", "we should increase coverage". The impulse is understandable, it feels like action. But without a risk map it's just guessing. You don't know if your integration tests address your highest-exposure risks, or if your load tests are covering the performance characteristics that actually threaten revenue.

This article starts from the ranked risk table you built in the previous one. From that table, you know what could go wrong, how likely it is, and how costly it would be. The question now is: which controls produce credible evidence for those risks, at what cost?

The bridge: mapping risks to quality characteristics

Before choosing testing activities, you need a way to connect "what could go wrong" to "what kind of testing addresses it". ISO 25010 gives you that bridge: eight product quality characteristics that serve as a shared vocabulary across teams.

The mapping heuristics are mostly intuitive once you're thinking in terms of what could go wrong:

  • Incorrect behavior or missing functionality: Functional suitability
  • Response time, throughput, resource use: Performance efficiency
  • Working with other systems, APIs, formats: Compatibility
  • User experience, ease of use, accessibility: Usability
  • Stability, availability, recovery: Reliability
  • Confidentiality, access control, threats: Security
  • Complexity, changeability, technical debt: Maintainability
  • Deployment targets, migration: Portability

A single risk can map to multiple characteristics. The payment regression risk maps to both functional suitability and reliability, the SQL injection risk maps to security and functional suitability. In my experience, trying to force a single label just makes the mapping less useful.

Once risks are categorized by quality characteristic, the testing menu shrinks: reliability risks point to reliability testing types, security risks to security testing types, and so on. That mapping drives every decision in the rest of this step.

Not all controls are tests

Before getting into testing decisions, it's worth stepping back: testing is not the only way to manage risk. Many of the highest-return controls aren't tests at all. For example:

  • Canary releases and blue/green deployments reduce the blast radius of a defect that slips through
  • Feature flags give you a kill switch in production
  • Monitoring and alerting tied to specific risks tells you when something is going wrong in real usage
  • WAF rules and input validation prevent entire classes of security risk before testing has to catch them
  • SLOs and error budgets work as release gates

Testing, your appraisal stream, produces evidence that these controls exist and work. When you're selecting controls for a given risk, the question is: what's the lowest-cost combination that produces credible evidence for this risk? Sometimes the answer includes operational controls that make testing cheaper or more targeted.

The evidence ladder

For each risk, there's a cost hierarchy worth respecting: the evidence ladder.

From cheapest to most expensive:

  1. Prevent via design and standards: coding standards, architecture patterns, threat modeling, design reviews.
  2. Detect via static review and analysis: code reviews, SAST, linters, requirements reviews.
  3. Detect via unit and component tests: fast, isolated checks.
  4. Detect via contract and integration tests: interface checks, API contracts, component integration.
  5. Detect via system and end-to-end tests: end-to-end scenarios, system integration.
  6. Detect via production guardrails and telemetry: SLOs, alerting, canaries, rollback automation.

The idea is to select the lowest rung that produces credible evidence for the risk. There's no point jumping to system tests when unit tests suffice, but you also can't rely on unit tests for risks that only show up at system scope.

Take the payment regression risk from the previous article (exposure 56, functional suitability and reliability). A calculation logic error is best caught at the unit level: fast, cheap, precise. An end-to-end checkout flow failure can only be confirmed at system level. So you match the level to the failure mode: unit for logic, system for flow. Starting at system level for logic errors is expensive and wasteful. Starting at unit level for system behavior is misleading: the tests pass but tell you nothing about the full flow.

I've found that this matching works best when you do it for each risk individually, rather than picking one level for the whole project.

Testing types: the "what"

Testing type defines which quality characteristic is being evaluated. Once you've mapped your risks to quality characteristics, the testing types follow naturally.

Our ranked risks from the previous article:

  • Payment regression (56) maps to functional suitability and reliability, so it needs functional testing and reliability testing.
  • Performance degradation (45) maps to performance efficiency, so it needs performance testing, load testing, and stress testing.
  • SQL injection (20) maps to security, so it needs security testing, penetration testing, and threat modeling (static).
  • Code complexity (72) maps to maintainability, so it needs code reviews and architecture reviews, both static.

The common pitfall here is selecting testing types based on "standard practice" rather than the risks you've actually identified. If maintainability is your highest-exposure risk (as it is here, at 72), that's a signal to invest heavily in code and architecture reviews, not to default to whatever the team has always done.

Test levels: the "where"

Test levels define where in the system hierarchy you produce evidence. Lower levels are faster and cheaper; higher levels are slower, costlier, and required for risks that only manifest at broader scope.

The levels, from narrowest to widest:

  • Unit and component: local logic, boundary conditions.
  • Component-integration and contract: interface mismatches, protocol and contract violations.
  • System: end-to-end behavior, configuration, cross-cutting concerns.
  • Acceptance: suitability for users, operations, regulations.
  • Field (alpha/beta): real-world usage in controlled conditions.

For the insulin pump from the first article, a dosing calculation error is a unit-level concern: the logic is local, the risk is catchable without a running system. But whether a patient can actually operate the device in a realistic use scenario is an acceptance-level concern, and no lower-level test can answer that question.

For the internal CMS, most of the interesting risk sits at the system and acceptance levels. The functionality is simple enough that unit tests add little; what matters is whether editors can do their work without friction.

The most expensive mistake I see teams make is defaulting to system and end-to-end tests for everything. It feels thorough, but it's actually slow, brittle, and expensive, and it provides no faster signal than you'd get from a well-targeted unit test for the same logic error.

Static vs dynamic: the balance

Static and dynamic testing are fundamentally different ways of producing evidence, and they catch different things.

Static testing (code reviews, SAST, requirements reviews, design inspections) examines artifacts without running the software. You can start it weeks before you have a working product. It catches insecure patterns, dependency issues, missing requirements, and unreachable states. Defects removed through static analysis are typically cheaper to fix because they're found earlier, before integration amplifies rework.

Dynamic testing requires an executing system. It's the only way to observe integration faults, concurrency and timing issues, performance under real load, actual security exposures, and UX problems. There's no way around it for those risks.

In my experience, the balance comes naturally if you start with static wherever the risk can be exposed early and cheaply, then add dynamic for risks that only appear during execution. For critical risks, use both.

Back to our four risks:

  • SQL injection: static first (code review, SAST), then dynamic (penetration testing). Both.
  • Performance degradation: static as an early signal (architecture review), then dynamic (load testing, which you cannot skip).
  • Code complexity: primarily static: code reviews, architecture reviews. This is the highest-exposure risk in our table and it's mostly a static concern. Investment here is cheap relative to the risk.
  • Payment regression: functional testing is dynamic. Requirements review and test-basis review are static. Both are valuable.

The failure mode I see often: teams skip static testing entirely and end up catching things in their dynamic test suite that a review three weeks earlier would have found at a fraction of the cost.

Test design techniques and coverage: the "how to derive"

Techniques define how you derive test cases and what coverage means. There are three families.

  • Specification-based (black-box): equivalence partitioning, boundary-value analysis, decision tables, state-transition testing, scenario testing. These work best when you have requirements or specifications to derive from.
  • Structure-based (white-box): statement, branch, and decision testing; MC/DC for safety-critical systems. These come into play when you need evidence about internal structure.
  • Experience-based: error guessing, exploratory testing. These complement the other two: they catch what specifications don't anticipate and what code structure doesn't reveal.

These aren't alternatives, but rather layers. For the payment regression risk, all three apply: equivalence partitioning covers valid and invalid amounts; branch coverage exercises all calculation paths; error guessing targets known rounding issues and currency edge cases. Each catches something the others might miss.

Coverage targets follow from risk priority:

  • High-priority risks: comprehensive coverage: all equivalence classes, all boundaries, all decision rules, branch coverage.
  • Medium-priority: key scenarios, main state transitions, representative paths.
  • Low-priority: happy path plus a small set of representative negatives.

Coverage shows how much of the test basis you exercised, not whether the test basis was complete to begin with. I think of coverage targets as minimum evidence thresholds, not quality guarantees. Whether they're actually reducing risk is something you find out when you review the portfolio, which is what the next article covers.

Test practices: the "how to execute"

Practices are orthogonal to types, levels, and techniques. They answer how testing is organized and executed: scripted or exploratory, manual or automated, and when it runs.

The taxonomy from ISO 29119 organizes practices around three decisions:

Exploratory vs scripted: exploratory testing is a practice suited to discovery, ambiguous scenarios, complex systems, and investigative security work. Scripted testing is suited to regression, compliance, and CI/CD gates, anything repeatable that benefits from consistency.

Manual vs automated: automation has upfront and maintenance cost. It pays off when checks run frequently and block expensive failures. Manual testing covers judgment-heavy work, one-off scenarios, and cases where the cost of automation exceeds the benefit of reuse.

Delivery cadence: on-commit CI gating for fast, cheap checks. Nightly or weekly regression for broader or slower suites. Pre-release hardening for final validation. Production canary for gradual rollout with real telemetry.

Matching practices to risks, from our table:

  • Payment regression: scripted automated, CI gating, plus a maintained regression suite. High priority, high frequency.
  • Performance degradation: automated on a nightly cadence. Can't gate commits on a full load test, but you want it running regularly.
  • SQL injection: periodic exploratory security sessions combined with automated SAST and security checks. You can't script your way to security confidence alone.
  • Code complexity: code reviews on every PR. No automation substitutes for the human judgment a good review provides.

The pitfall I see most often: over-automating judgment-heavy work (high maintenance, low signal) and under-automating repetitive high-frequency checks (slow feedback, inconsistent execution). The decision about what to automate should follow the same risk-based logic as every other decision in this process.

Overlap and coverage gaps

Every testing activity can address multiple risks, and multiple activities can address the same risk. Overlap is normal, it provides safety margins. The question is whether the overlap is buying anything.

Good redundancy is diverse and low-correlation: static plus dynamic, unit plus contract, specification-based plus experience-based. Different oracles catching different things. When the checks are genuinely different, redundancy buys confidence.

Bad redundancy is correlated: the same functional check at unit, integration, and system levels. Same oracle, same signal, three times the cost. It looks thorough but it isn't.

The real danger isn't over-overlap, it's under-coverage. Risks with no evidence stream at all.

Our SQL injection risk scores 20 in the table, borderline, treated as "acceptable with controls". But if the portfolio has no SAST, no penetration testing, no security reviews, and no WAF configuration, that's not a plan. Every high-exposure risk should have at least one credible evidence stream. I'd recommend walking the list: if any risk has nothing pointing at it, that's a gap, not an acceptable decision.

The traceability chain

The output of this process is not just a list of testing activities. It's a traceable mapping: risk → controls → evidence → acceptance decision → review metrics.

Each testing activity traces back to the risk it addresses. When management asks "why are we running load tests?", you point at the performance degradation risk with exposure 45 and their sign-off on it. When the performance risk changes (new architecture, new traffic patterns, new SLO), you know exactly which testing to revisit.

Traceability makes the conversations concrete. "We're not testing for SQL injection more aggressively because the exposure score is 20 and we have WAF controls in place" works because anyone can look at the risk table, see the score, check the controls, and agree or disagree with the rationale. And since stakeholders signed off on the risk priorities together, the decision is shared, not something one team has to defend alone.

What you have at the end

At this point:

  • Risks are mapped to quality characteristics.
  • Testing types, levels, techniques, and practices are selected per risk.
  • The static/dynamic balance is decided, with rationale.
  • Coverage targets are set proportional to risk priority.
  • Overlap is intentional and diverse; coverage gaps are identified and either addressed or accepted with rationale.
  • Every testing activity traces back to the risk it addresses.

This is your testing strategy. Not a template, not a list of tools, not a coverage number, not a "best practice", but a portfolio with explicit rationale that you can explain, defend, and adjust as conditions change.

The next article is about closing the loop: reviewing the portfolio against actual outcomes, rebalancing where the evidence isn't reducing risk as expected, and adjusting when risks change. That's where the strategy becomes a continuous process rather than a one-time plan.

The full research behind this series is at BeyondQuality.

You've successfully subscribed to Qase Blog | Articles about our product, software testing and the QA community.
Great! Next, complete checkout to get full access to all premium content.
Error! Could not sign up. invalid link.
Welcome back! You've successfully signed in.
Error! Could not sign in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.