Exploratory Testing
Scripted test cases check what you already expect. But the worst bugs are usually the ones nobody wrote a test case for: paying during a network drop, tapping "Pay" twice, pasting Hindi text into a name field. Exploratory testing finds these by letting a skilled tester learn the product, design tests and run them at the same time.
In this lesson you will learn what exploratory testing is and is not, how to run a timeboxed session with a charter, the heuristics testers use to generate ideas, and how a few lines of code can explore hundreds of variations for you.
What exploratory testing is
In scripted testing, design and execution are separated: someone writes the test cases first, and someone (maybe a different person) runs them later. In exploratory testing, the tester designs the next test based on what the last one revealed. Learning, test design and execution happen together, and the tester keeps notes so the work can be reported and repeated.
It is not random clicking. A good exploratory tester has a goal, a time limit, a method for generating ideas and a record of what was done. The output is a list of bugs, a list of questions for the team, and knowledge about the product.
| Scripted testing | Exploratory testing | |
|---|---|---|
| Tests designed | In advance, from requirements | During the session, from observation |
| Best for | Repeating known checks, regulated systems, automation | New features, unclear requirements, finding unexpected bugs |
| Repeatability | High | Depends on the notes taken |
| Depends on | Good documents | A skilled, curious tester |
Most teams do both: scripted and automated tests protect what is known, and exploratory sessions hunt for what is not.
Session-based test management
To make exploration accountable, testers run it in sessions: timeboxed blocks of 60 to 120 minutes with a written charter that says what to explore and why. A common charter template is:
Explore <area or feature>
with <resources, tools, data or conditions>
to discover <kind of information or risk>For example: "Explore UPI checkout with a slow and dropping network to discover payment state problems." The charter keeps the tester focused but leaves them free to choose the exact actions.
During the session the tester keeps a simple log: what they set up, what they tested, bugs found and questions raised. At the end they debrief with the team. This JavaScript example summarises such a log, the way a session report tool would:
const session = {
charter: "Explore UPI checkout with poor network to discover payment state problems",
tester: "Ananya",
timeboxMinutes: 60,
log: [
{ minutes: 8, kind: "setup", note: "Installed build 4.2.1, enabled network throttling" },
{ minutes: 20, kind: "test", note: "Paid, switched to airplane mode during redirect" },
{ minutes: 12, kind: "bug", note: "Order shows FAILED but money was debited" },
{ minutes: 15, kind: "test", note: "Back button and refresh on payment page" },
{ minutes: 5, kind: "bug", note: "Double tap on Pay creates two orders" },
],
questions: ["What should the app show while the bank has not answered?"],
};
const totals = {};
for (const entry of session.log) {
totals[entry.kind] = (totals[entry.kind] ?? 0) + entry.minutes;
}
const used = Object.values(totals).reduce((a, b) => a + b, 0);
console.log(`Charter: ${session.charter}`);
console.log(`Time used: ${used} of ${session.timeboxMinutes} minutes`);
for (const [kind, minutes] of Object.entries(totals)) {
console.log(` ${kind.padEnd(6)} ${Math.round((minutes / used) * 100)}%`);
}
console.log("Bugs:", session.log.filter((e) => e.kind === "bug").map((e) => e.note));
console.log("Open questions:", session.questions.length);Charter: Explore UPI checkout with poor network to discover payment state problems Time used: 60 of 60 minutes setup 13% test 58% bug 28% Bugs: [ 'Order shows FAILED but money was debited', 'Double tap on Pay creates two orders' ] Open questions: 1
The split between setup, testing and bug reporting tells a test lead how productive the session was and whether setup problems are eating time.
Heuristics: where ideas come from
A heuristic is a rule of thumb that helps you think of tests. Experienced testers carry many; here are some you can use from day one:
- Boundaries and emptiness. Zero, one, many; empty, full, over the limit (see Equivalence Partitioning & Boundary Values).
- Interruptions. Close the app, lose the network, get a phone call, let the screen lock, press Back, refresh.
- Repetition. Do it twice: double click, submit the same form again, apply a coupon two times.
- Sequence. Do steps in the wrong order, skip a step, go back and change an earlier step.
- Data variety. Other scripts and languages, emojis, very long text, leading and trailing spaces, special characters.
- Roles and permissions. Try an action as a logged-out user, a normal user and an admin.
- Environment. Small screen, large font setting, slow 3G, different time zone, dark mode.
- Follow the data. Where does a value go after you enter it? Check the receipt, the email, the admin page and the export file.
A short list like this, pinned next to your monitor, turns "I do not know what to try" into an hour of good ideas.
Exploring with code
Exploration is not only manual. When you suspect a function is fragile, a few lines of code can try hundreds of variations faster than you can type them. Here a tester explores an amount parser used in a shopping app's price import, trying every combination of currency prefixes and number formats people actually type:
from itertools import product
def parse_amount(text):
"""Turn text such as 'Rs 1,299.50' or '₹ 450' into paise (1 rupee = 100 paise)."""
cleaned = text.replace("₹", "").replace("Rs", "").replace(",", "").strip()
rupees, _, paise = cleaned.partition(".")
return int(rupees) * 100 + int(paise.ljust(2, "0")[:2])
prefixes = ["₹", "₹ ", "Rs ", "Rs. ", "INR "]
numbers = ["450", "1,299.50", "12,00,000", ".75"]
problems = []
for prefix, number in product(prefixes, numbers):
text = prefix + number
try:
parse_amount(text)
except ValueError as error:
problems.append(f"{text!r:<16} {error}")
print(f"Tried {len(prefixes) * len(numbers)} variations, {len(problems)} crashed:")
for line in problems:
print(" ", line)Tried 20 variations, 11 crashed: '₹.75' invalid literal for int() with base 10: '' '₹ .75' invalid literal for int() with base 10: '' 'Rs .75' invalid literal for int() with base 10: '' 'Rs. 450' invalid literal for int() with base 10: '' 'Rs. 1,299.50' invalid literal for int() with base 10: '' 'Rs. 12,00,000' invalid literal for int() with base 10: '' 'Rs. .75' invalid literal for int() with base 10: '' 'INR 450' invalid literal for int() with base 10: 'INR 450' 'INR 1,299.50' invalid literal for int() with base 10: 'INR 1299' 'INR 12,00,000' invalid literal for int() with base 10: 'INR 1200000' 'INR .75' invalid literal for int() with base 10: 'INR '
Three findings in a few seconds: the common Indian form Rs. with a dot breaks the parser, INR is not handled at all, and an amount with no rupee part (.75) crashes. Each becomes a bug report or a question for the product owner ("should we accept INR?"). The exploration itself took a minute to write.
Reporting what you found
Exploratory testing produces value only if it is written down. After each session record:
- the charter and the time spent;
- which areas were covered and which were not;
- bugs, each written as a proper report (see Bug Life Cycle & Bug Reports);
- questions and risks for the team;
- ideas for new scripted or automated tests.
That last point matters: bugs found by exploration often become permanent regression tests, so the same problem can never return unnoticed.
Common mistakes
- No charter. Without a goal, a session drifts and nothing can be reported.
- No notes. A bug you cannot reproduce because you forgot the steps is a wasted find.
- Only exploring. Teams that drop scripted and automated tests lose their safety net for known behaviour.
- Stopping at the first bug. Log it briefly and continue; write the full report after the session.
Key points
- Exploratory testing designs, runs and learns from tests at the same time, guided by a skilled tester.
- Sessions are timeboxed and have a charter: explore an area, with certain resources, to discover a kind of risk.
- Heuristics such as interruptions, repetition, sequence and data variety generate test ideas quickly.
- Small scripts can explore hundreds of input variations in seconds.
- Record coverage, bugs, questions and ideas for new automated tests after every session.
Exercise
Write a charter for exploring the "forgot password" feature of a college portal, using the three-line template. Then list six test ideas for it, using at least four different heuristics from this lesson (name the heuristic next to each idea).
Show solution
Explore the forgot-password flow
with two test accounts, a second phone and network throttling
to discover ways a student could be locked out or an attacker could get inTest ideas:
- Interruptions: request an OTP, switch off the network, switch it back on, then enter the OTP.
- Repetition: tap "Send OTP" five times quickly and check how many SMS arrive and which one works.
- Sequence: request an OTP, request a second one, then enter the first OTP.
- Boundaries: enter the OTP at exactly the expiry time and one second after.
- Data variety: enter an email with capital letters and trailing spaces.
- Roles: open the reset link while already logged in as a different student.
Each idea states an action and a thing to observe, which is enough to start exploring and to write a bug report if something fails.
Quick Quiz
1. What makes exploratory testing different from scripted testing?
In exploratory testing the next test is chosen from what the previous test revealed.
2. What does a charter contain?
A charter sets the goal and scope of a session without prescribing the exact actions.
3. "Tap Pay twice quickly" is an example of which heuristic?
Doing an action more than once checks for duplicate orders, charges or messages.
4. Why keep notes during an exploratory session?
Notes turn exploration into reproducible bugs, reportable coverage and ideas for automated tests.
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
