Test Plans & Strategy
Testing without a plan turns into clicking around until the deadline. A test plan says what will be tested, how, by whom, when and how you will know you are done. A test strategy describes the general approach an organisation or product follows across many projects. Both exist so that the whole team agrees on scope and risk before the pressure of a release.
In this lesson you will learn what goes into a test plan, how risk-based testing decides where to spend effort, how to estimate test effort, and how to track progress with a few simple metrics.
Test strategy and test plan
| Test strategy | Test plan | |
|---|---|---|
| Scope | Organisation, product line or programme | One project, release or sprint |
| Changes | Rarely | For every release |
| Answers | What kinds of testing do we always do, with which tools and standards? | What exactly will we test in this release, by when and by whom? |
| Example content | "Every API has automated contract tests; UI tests use Playwright" | "Release 4.2 adds UPI autopay; three testers, 10 working days" |
Small teams often merge the two into one living document or a wiki page. That is fine; what matters is that the decisions are written down and agreed.
What goes into a test plan
Older projects followed the IEEE 829 template; its successor, the ISO/IEC/IEEE 29119-3 standard, describes similar content. You do not need to follow a standard word for word. A practical plan covers:
test_plan: Release 4.2 - Kirana Kart mobile app
objectives: Confirm UPI autopay and the new cart work for real shop owners
scope:
in: [UPI autopay setup, cart, invoice with GST, Android app]
out: [iOS app (next release), admin reports]
approach:
levels: [unit, integration, system, acceptance]
types: [functional, regression, performance smoke, security basics]
automation: Regression suite in pytest and Playwright, run on every merge
environment: Staging server, Android 13-15 devices, sandbox payment gateway
entry_criteria: Build deployed to staging and smoke tests passing
exit_criteria: 95% of planned tests passed, no open Critical or P1 bugs
schedule: 10 working days from build handover
team: [Priya (lead), Kabir, Isha]
risks:
- Payment sandbox may be unstable; mitigation is a stub for non-payment tests
deliverables: [test cases, daily status, bug reports, summary report]Each line answers a question someone will otherwise ask in a panic later: "Was iOS in scope?", "Which devices?", "When are we done?". Entry and exit criteria were introduced in SDLC & STLC.
Risk-based testing
You never have time to test everything equally, so spend effort where failure would hurt most. Risk-based testing rates each product risk by likelihood (how likely is a defect here?) and impact (how bad would a failure be?), multiplies them into a score, and tests the highest scores most thoroughly and earliest.
risks = [
("UPI payment fails or double-charges", 4, 5),
("Wrong GST on invoice", 3, 4),
("Search returns slow results", 3, 2),
("Profile photo upload fails", 2, 2),
("Order tracking map misplaces pin", 2, 3),
]
print(f"{'Risk':<38}{'L':>2}{'I':>3}{'Score':>7} Test depth")
for name, likelihood, impact in sorted(risks, key=lambda r: r[1] * r[2], reverse=True):
score = likelihood * impact
depth = "Thorough" if score >= 12 else "Standard" if score >= 6 else "Light"
print(f"{name:<38}{likelihood:>2}{impact:>3}{score:>7} {depth}")Risk L I Score Test depth UPI payment fails or double-charges 4 5 20 Thorough Wrong GST on invoice 3 4 12 Thorough Search returns slow results 3 2 6 Standard Order tracking map misplaces pin 2 3 6 Standard Profile photo upload fails 2 2 4 Light
Likelihood rises with new or complex code, many recent bugs (remember that defects cluster) and inexperienced teams. Impact rises with money, legal duties, safety and the number of users affected. The scores are judgements, so agree them as a team; the value lies in the discussion as much as the numbers.
Estimating test effort
Managers will ask "how long will testing take?". A simple and widely used method is the three-point estimate: for each task, estimate an optimistic (O), most likely (M) and pessimistic (P) duration, then combine them as (O + 4M + P) / 6. The weighting pulls the result towards the most likely value while still allowing for things going wrong.
tasks = {
"Write test cases": (3, 5, 10),
"Set up test environment": (1, 2, 6),
"Run functional tests": (4, 6, 9),
"Regression and retesting": (2, 3, 7),
}
total = 0
for task, (optimistic, likely, pessimistic) in tasks.items():
estimate = (optimistic + 4 * likely + pessimistic) / 6
total += estimate
print(f"{task:<26} {estimate:4.1f} days")
print(f"{'Total':<26} {total:4.1f} days")Write test cases 5.5 days Set up test environment 2.5 days Run functional tests 6.2 days Regression and retesting 3.5 days Total 17.7 days
Other approaches include using data from similar past releases and, in agile teams, estimating together in story points. Always remember to include time for retesting fixed bugs and for regression runs, which beginners forget.
Monitoring and control
Once execution starts, the test lead compares progress with the plan every day (monitoring) and adjusts when things slip (control): moving people, cutting low-risk tests or asking for more time. A few metrics are enough for most projects:
- Execution progress: tests run out of tests planned.
- Pass rate: passed out of executed.
- Defects: open bugs by severity and priority, found and fixed per day.
- Blocked tests: tests that cannot run because of environment or bugs.
const planned = 240;
const days = [
{ day: "Mon", executed: 45, passed: 38 },
{ day: "Tue", executed: 52, passed: 47 },
{ day: "Wed", executed: 40, passed: 36 },
{ day: "Thu", executed: 48, passed: 45 },
];
let executed = 0;
let passed = 0;
for (const d of days) {
executed += d.executed;
passed += d.passed;
const progress = ((executed / planned) * 100).toFixed(0);
console.log(`${d.day}: executed ${executed}/${planned} (${progress}%), pass rate ${((passed / executed) * 100).toFixed(1)}%`);
}
const perDay = executed / days.length;
console.log(`Days needed for the remaining ${planned - executed} tests: ${Math.ceil((planned - executed) / perDay)}`);Mon: executed 45/240 (19%), pass rate 84.4% Tue: executed 97/240 (40%), pass rate 87.6% Wed: executed 137/240 (57%), pass rate 88.3% Thu: executed 185/240 (77%), pass rate 89.7% Days needed for the remaining 55 tests: 2
The pass rate is rising as fixes arrive, and at the current pace the remaining tests need two more days. If the release is tomorrow, the lead must raise this today, not on release morning.
At the end, a test summary report states what was tested, what was not, the final metrics, open risks and a recommendation, so stakeholders can make an informed release decision.
Common mistakes
- A plan nobody reads. Keep it short, link it from the team's board and update it when scope changes.
- No "out of scope" section. Unstated exclusions become surprises after release.
- Equal effort everywhere. Spending as long on the profile photo as on payments is a planning failure.
- Reporting only pass counts. Also report what was not tested and the risks that remain.
Key points
- A test strategy is the long-term approach; a test plan is the concrete plan for one release.
- A plan covers objectives, scope in and out, approach, environment, entry and exit criteria, schedule, team, risks and deliverables.
- Risk-based testing scores likelihood times impact and tests the highest risks first and deepest.
- The three-point estimate (O + 4M + P) / 6 gives a balanced effort estimate.
- Monitor progress, pass rate, defects and blocked tests daily, and end with a test summary report.
Exercise
A college admission portal in Lucknow will open in two weeks. List five product risks for it, give each a likelihood and impact from 1 to 5, and change the risk program to print them in order with a suggested test depth. Then write two exit criteria for this release.
Show solution
risks = [
("Fee payment charged but form not submitted", 3, 5),
("Merit list rank calculated wrongly", 2, 5),
("Site slows down on the last date", 4, 4),
("Document upload rejects valid PDFs", 3, 3),
("Confirmation email has wrong course name", 2, 2),
]
for name, likelihood, impact in sorted(risks, key=lambda r: r[1] * r[2], reverse=True):
score = likelihood * impact
depth = "Thorough" if score >= 12 else "Standard" if score >= 6 else "Light"
print(f"{score:>2} {depth:<9} {name}")16 Thorough Site slows down on the last date 15 Thorough Fee payment charged but form not submitted 10 Standard Merit list rank calculated wrongly 9 Standard Document upload rejects valid PDFs 4 Light Confirmation email has wrong course name
Example exit criteria: "All Thorough-risk test cases have passed" and "the portal handles the expected last-day load in a performance test with no Critical bugs open". Note that the merit-list risk has a top impact score; many teams would test it thoroughly anyway, because its impact on students is so high.
Quick Quiz
1. Which document usually covers many projects and changes rarely?
A strategy sets the general approach; a plan applies it to one release.
2. In risk-based testing, what two ratings make up the risk score?
Product risk is rated by how likely a failure is and how bad its impact would be.
3. Using the three-point estimate, what is the estimate for O = 2, M = 4, P = 12 days?
(2 + 4 x 4 + 12) / 6 = 30 / 6 = 5 days.
4. Why should a test plan have an "out of scope" section?
Writing down exclusions turns hidden assumptions into agreed decisions.
Learn Software Testing with a mentor
Free lessons get you started. Our Software Testing training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
