How to Write Test Cases for OTP Verification (With Examples)
How to Write Test Cases for Otp Verification (With Examples) begins with a clear grasp of the OTP flow and ends with a reusable test matrix.
How to Write Test Cases for Otp Verification (With Examples) begins with a clear grasp of the OTP flow and ends with a reusable test matrix.
This guide walks you through every step needed to design high‑signal test cases for one‑time password verification, from flow analysis to traceability, and shows how manual design pairs with autonomous exploration to achieve real coverage.
Understanding OTP Verification Flow
Before writing any test case, map the end‑to‑end process that the system follows when a user requests and validates an OTP. A typical flow includes:
- Trigger – user clicks “Send OTP” or system initiates verification (e.g., login, password reset, payment).
- Request Generation – backend creates a random numeric or alphanumeric code, stores it with expiry timestamp and usage limit, and dispatches it via SMS, email, push, or voice.
- Delivery – the user receives the code through the chosen channel.
- Input – user enters the code into the UI field.
- Validation – backend checks code correctness, expiry, and reuse constraints; returns success or failure response.
- Post‑validation Action – on success, the system proceeds to the protected operation (e.g., grants access, resets password); on failure, it shows an error and may allow retries.
Identify all touchpoints where variations can occur: channel latency, code format, resend limits, brute‑force protection, accessibility of the input field, and handling of expired or already‑used codes.
Why Flow Mapping Matters
A test case that only checks “correct code → success” misses failure modes that appear only when a preceding step behaves unexpectedly. By documenting each step, you can derive preconditions, inputs, and expected results that target specific risks.
Anatomy of a Robust Test Case
A well‑structured test case contains the following elements:
| Element | Description | Example for OTP |
|---|---|---|
| ID | Unique identifier (e.g., OTP‑001) | OTP‑001 |
| Title | Short, readable summary | “Valid OTP entered within expiry leads to successful login” |
| Preconditions | State that must be true before execution | User is on login screen, phone number verified, OTP service configured |
| Steps | Numbered actions performed by tester or script | 1. Tap “Send OTP”. 2. Wait for SMS. 3. Enter 6‑digit code. 4. Tap “Verify”. |
| Test Data | Specific values used | Code = 123456, expiry = 120 s |
| Expected Result | Observable outcome | System navigates to home screen, shows welcome toast |
| Postconditions | System state after test (if needed) | Session token stored, user authenticated |
| Priority | P0‑P3 based on risk | P0 |
| Traceability | Link to requirement or user story | REQ‑OTP‑01, REQ‑OTP‑07 |
Each element forces you to think about what you are validating and makes the case reusable across manual and automated suites.
Writing Steps That Are Automation‑Friendly
Use imperative language that maps directly to UI actions or API calls. Avoid vague phrasing like “check that the OTP works”. Instead, write:
- “Enter the exact six‑digit code received in the SMS into the OTP input field.”
- “Press the Verify button and observe the HTTP response status 200 with JSON
{ \"status\": \"success\" }.”
When steps are precise, test engineers can translate them into Appium, Playwright, or Selenium scripts with minimal interpretation.
Positive Test Cases for OTP Verification
Positive cases verify that the system behaves correctly when everything works as intended. Below is a representative set; you can expand based on channel specifics.
| ID | Preconditions | Steps | Expected Result |
|---|---|---|---|
| OTP‑POS‑01 | User on login screen, valid phone number registered | 1. Tap “Send OTP”. 2. Receive SMS with code 654321. 3. Enter 654321. 4. Tap Verify. | System logs user in, redirects to dashboard, shows success toast. |
| OTP‑POS‑02 | User requesting password reset, email verified | 1. Click “Forgot Password”. 2. Enter email, tap Send OTP. 3. Receive email with code 987654. 4. Input code, tap Verify. 5. Enter new password, tap Submit. | Password updated, user prompted to log in with new credentials. |
| OTP‑POS‑03 | User performing a payment, OTP via push notification | 1. Add item to cart, proceed to checkout. 2. Choose credit card, tap Pay. 3. Receive push OTP 123‑456. 4. Enter code, tap Confirm. | Payment authorized, order confirmation page shown, email receipt sent. |
| OTP‑POS‑04 | User enrolling a new device, OTP via voice call | 1. In Settings, tap “Add Device”. 2. Choose voice call, enter phone number. 3. Receive call, hear spoken code 321098. 4. Enter code, tap Verify. | Device added, appears in device list, session token refreshed. |
| OTP‑POS‑05 | User resending OTP after expiry, SMS channel | 1. Tap Send OTP, receive code, wait 130 s (expired). 2. Tap Resend OTP. 3. Receive new code 111222. 4. Enter code, tap Verify. | New code accepted, login succeeds. |
| OTP‑POS‑06 | User enters OTP with leading zeros (e.g., 001234) | 1. Send OTP, receive code 001234. 2. Enter exactly as shown, tap Verify. | System treats leading zeros as significant, login succeeds. |
| OTP‑POS‑07 | User enters OTP via autocomplete from native OS suggestion bar | 1. Send OTP, receive SMS. 2. OS shows suggestion bar with code. 3. Tap suggestion to fill field. 4. Tap Verify. | Login succeeds, same as manual entry. |
| OTP‑POS‑08 | User enters OTP after copying from clipboard (long‑press paste) | 1. Send OTP, receive SMS. 2. Long‑press SMS, copy code. 3. Long‑press OTP field, paste. 4. Tap Verify. | Login succeeds. |
| OTP‑POS‑09 | User enters OTP with spaces auto‑stripped by system (e.g., “12 34 56”) | 1. Send OTP, receive code 123456. 2. Enter “12 34 56” (spaces). 3. Tap Verify. | System ignores spaces, treats as 123456, login succeeds. |
| OTP‑POS‑10 | User completes OTP flow under low‑network condition (simulated 3G) | 1. Enable network throttling to 3G. 2. Send OTP, wait for delayed SMS. 3. Enter code, tap Verify. | Login succeeds after slight delay, no timeout error. |
These cases cover happy‑path scenarios across channels, input methods, and environmental factors.
Negative Test Cases for OTP Verification
Negative cases ensure the system rejects invalid input and enforces security controls.
| ID | Preconditions | Steps | Expected Result |
|---|---|---|---|
| OTP‑NEG‑01 | User on login screen, OTP sent | 1. Enter incorrect 6‑digit code (e.g., 000000). 2. Tap Verify. | System shows error “Invalid OTP”, remains on login screen, allows retry. |
| OTP‑NEG‑02 | User on login screen, OTP sent | 1. Leave OTP field blank. 2. Tap Verify. | System shows field‑level validation error “OTP is required”. |
| OTP‑NEG‑03 | User on login screen, OTP sent | 1. Enter more than six digits (e.g., 1234567). 2. Tap Verify. | System rejects input, shows “OTP must be 6 digits”. |
| OTP‑NEG‑04 | User on login screen, OTP sent | 1. Enter non‑numeric characters (e.g., abcdef). 2. Tap Verify. | System shows “OTP must contain only numbers”. |
| OTP‑NEG‑05 | User on login screen, OTP sent | 1. Enter correct code after expiry (wait 130 s). 2. Tap Verify. | System shows “OTP has expired”, forces resend. |
| OTP‑NEG‑06 | User on login screen, OTP sent | 1. Enter correct code, tap Verify (first success). 2. Immediately re‑enter same code, tap Verify again. | System shows “OTP already used”, denies second verification. |
| OTP‑NEG‑07 | User on login screen, OTP sending rate‑limit in place | 1. Tap Send OTP five times within 10 s. 2. On fifth attempt, observe response. | System blocks further sends, shows “Too many requests, try later”. |
| OTP‑NEG‑08 | User on login screen, OTP via SMS, SIM‑swap scenario simulated | 1. Send OTP to original number. 2. Change backend phone number to attacker‑controlled. 3. Attempt to use OTP sent to old number. | System rejects OTP because phone number mismatch, logs security event. |
| OTP‑NEG‑09 | User on login screen, OTP field accessible via screen reader | 1. Enable TalkBack, focus OTP field. 2. Enter incorrect code via accessibility service. 3. Tap Verify. | System reads error message aloud, does not proceed. |
| OTP‑NEG‑10 | User on login screen, OTP request tampered (MITM) | 1. Intercept OTP request via proxy, modify code_length parameter to 4. 2. Receive 4‑digit code. 3. Enter 4‑digit code, tap Verify. | Backend rejects due to length mismatch, returns error. |
These cases test validation, expiry, replay protection, rate limiting, and integrity of the OTP binding to the user identifier.
Edge and Boundary Cases for OTP Verification
Edge cases live at the limits of specifications and often surface only under stress or unusual user behavior.
| ID | Preconditions | Steps | Expected Result |
|---|---|---|---|
| OTP‑EDG‑01 | System allows OTP length configurable (4‑8 digits) | 1. Configure backend for 4‑digit OTP. 2. Send OTP, receive 1234. 3. Enter 1234, tap Verify. | Login succeeds with 4‑digit code. |
| OTP‑EDG‑02 | Same as above, but user enters 5‑digit code | 1. Enter 12345, tap Verify. | System shows “OTP must be 4 digits”. |
| OTP‑EDG‑03 | OTP expiry configurable (30‑300 s) | 1. Set expiry to 30 s. 2. Send OTP, wait 31 s. 3. Enter code, tap Verify. | System shows “OTP expired”. |
| OTP‑EDG‑04 | Maximum resend attempts limited (e.g., 3) | 1. Tap Send OTP three times quickly. 4. Tap Send OTP a fourth time. | System blocks fourth send, shows “Resend limit reached”. |
| OTP‑EDG‑05 | OTP contains repeating digits (111111) | 1. Send OTP, receive 111111. 2. Enter 111111, tap Verify. | Login succeeds; no special handling needed. |
| OTP‑EDG‑06 | OTP contains sequential digits (123456) | 1. Send OTP, receive 123456. 2. Enter 123456, tap Verify. | Login succeeds. |
| OTP‑EDG‑07 | User pastes OTP with trailing newline from clipboard | 1. Copy OTP from SMS (includes newline). 2. Paste into field, tap Verify. | System trims whitespace, login succeeds. |
| OTP‑EDG‑08 | User enters OTP using voice‑to‑text (speech input) | 1. Activate dictation, speak “one two three four five six”. 2. System inserts “123456”. 3. Tap Verify. | Login succeeds if transcription accurate; otherwise shows error. |
| OTP‑EDG‑09 | OTP delivery channel fails (SMS gateway down) | 1. Disable SMS gateway in test environment. 2. Tap Send OTP. 3. Observe fallback or error. | System shows “Unable to send OTP, try email or try later”. |
| OTP‑EDG‑10 | Concurrent OTP requests for same user (different sessions) | 1. Open two browser tabs, both trigger Send OTP simultaneously. 2. Receive two different codes. 3. Enter code from tab A in tab B, tap Verify. | System rejects because code not associated with that session/binding. |
These cases probe configurability, input sanitization, fallback mechanisms, and race conditions.
Data Setup, Test Environment, and Prioritization
Test Data Management
- Phone numbers / emails: Use a pool of dedicated test numbers that can receive real SMS or use a mock SMS gateway (e.g., Twilio test credentials, MessageBird sandbox).
- Codes: Pre‑generate a set of known codes and store them in a test data repository; alternatively, hook into the OTP generation API to fetch the latest code for a given identifier.
- Timestamps: Control system clock or use a library like
timewrapto shift expiry without waiting real time. - Network conditions: Leverage tools such as
tc(Linux traffic control), Network Link Conditioner (macOS), or Android’sadb shell netcfgto simulate latency, packet loss, or bandwidth limits.
Environment Checklist
| Component | Recommended Setting | Reason |
|---|---|---|
| Test device/emulator | Android 10+ or iOS 14+ with latest security patches | Ensures OTP APIs behave as in production |
| Mock OTP provider | Configurable latency, success/failure toggles | Allows injection of delayed or failed deliveries |
| Logging | Capture request/response payloads, OTP generation events | Facilitates root cause analysis |
| Security | Disable rate‑limit bypass in test mode only; re‑enable for CI | Prevents accidental abuse while testing limits |
| Accessibility | TalkBack/VoiceOver enabled | Validates error messages are announced |
Prioritization Framework
Apply a simple risk‑based matrix:
| Impact \ Likelihood | Low | Medium | High |
|---|---|---|---|
| Critical (security, compliance) | P2 | P1 | P0 |
| Major (core functionality loss) | P3 | P2 | P1 |
| Minor (UI glitch, cosmetic) | P4 | P3 | P2 |
| Trivial (spelling, rare edge) | P5 | P4 | P3 |
Assign each test case a priority based on where it falls. For example:
- OTP‑NEG‑06 (replay attack) → Impact Critical, Likelihood Medium → P1
- OTP‑POS‑07 (autocomplete) → Impact Minor, Likelihood High → P3
- OTP‑EDG‑09 (SMS gateway failure) → Impact Major, Likelihood Low → P3
Prioritization guides execution order in manual runs and helps decide which cases to automate first.
Manual Execution vs Automated Scripts
Manual Testing Strengths
- Exploratory intuition: testers can notice odd UI behavior, misaligned placeholders, or accessibility quirks that scripts miss.
- Ad‑hoc variations: quickly try unconventional input methods (voice, paste from unusual sources).
- Immediate feedback: tester can ask “does this feel right?” and note subjective UX friction.
Automation Strengths
- Repeatability: run the same steps hundreds of times per CI pipeline.
- Speed: a suite of 20 OTP cases executes in under two minutes on a device farm.
- Data‑driven: easily iterate over dozens of phone numbers, code values, and timing scenarios.
Sample Automation Snippets
#### Appium (Java) – Positive SMS OTP
@Test
public void testValidSmtpOtpLogin() {
// 1. Trigger OTP send
driver.findElement(By.id("btn_send_otp")).click();
// 2. Retrieve OTP from mock SMS gateway (REST call)
String otp = HttpHelper.getOtpFromMockGateway(testUser.getPhone());
// 3. Enter OTP
WebElement otpField = driver.findElement(By.id("otp_input"));
otpField.sendKeys(otp);
// 4. Verify
driver.findElement(By.id("btn_verify")).click();
// 5. Assert landing page
Assert.assertTrue(driver.findElement(By.id("home_screen")).isDisplayed());
}
#### Playwright (TypeScript – Negative expiry
test('expired OTP is rejected', async ({ page }) => {
await page.goto('/login');
await page.click('text=Send OTP');
// fast‑forward clock 150 s (assuming test helper)
await page.evaluate(() => { /* mock OTP service to return expired timestamp */ });
const otp = await getOtpFromMock(page);
await page.fill('#otp_input', otp);
await page.click('text=Verify');
await expect(page.locator('.error')).toHaveText('OTP has expired');
});
#### Bash CLI – Trigger SUSATest Exploration
# Install the agent
pip install susatest-agent
# Run a 5‑minute exploratory session on an Android APK
susatest explore --app ./myapp.apk \
--personas curious impatient elderly \
--max-duration 5m \
--output ./susatest-report.json
The agent will automatically attempt OTP flows, vary input timing, and log any crashes, ANRs, or validation failures it discovers.
Leveraging Autonomous Exploration with SUSATest
While hand‑crafted test cases provide depth, autonomous exploration adds breadth by exercising the app in ways a tester may not anticipate.
How SUSATest Works
- Ingestion – You supply an APK (Android) or a web URL.
- Personas – The agent simulates distinct behavior profiles (e.g., impatient users tap rapidly, elderly users linger, adversarial users fuzz inputs).
- Exploration – It navigates screens, fills fields, handles dialogs, and attempts real user flows such as login, signup, or checkout.
- Observation – It logs crashes, ANRs, dead buttons, WCAG violations, security hints, and UX friction.
- Script Generation – From successful paths it auto‑creates regression scripts in Appium (Android) and Playwright (Web).
Integrating SUSATest with OTP Verification
- Pre‑seed – Provide a test phone number that the agent can use; configure a mock OTP service that returns predictable codes.
- Persona‑Specific Variations – The curious persona may try to re‑send OTP many times; the impatient persona may spam the Verify button; the adversarial persona may inject SQL‑like strings into the OTP field.
- Outcome Correlation – After a run, compare the agent’s discovered paths against your manual test matrix. Any path not covered by your cases becomes a candidate for a new test case.
#### Example: Discovering a Race Condition
During an exploratory run, the adversarial persona triggered two OTP requests within 200 ms, received two distinct codes, and attempted to verify the first code in the second session. The agent logged a failure: “OTP verification succeeded despite session mismatch”. This insight led to adding a new test case (OTP‑EDG‑10) to the matrix.
Benefits
- Coverage boost – Autonomous runs often hit edge cases like rapid resend, out‑of‑order verification, or accessibility‑driven input methods that are easy to overlook.
- Regression safety – Auto‑generated scripts become part of your CI pipeline, guarding against future changes that break OTP flow are caught early.
- Learning loop – Each run refines the agent’s model of the app, making subsequent explorations smarter and reducing false positives.
Limitations
- The agent does not replace domain‑specific reasoning; it cannot infer business rules like “OTP must be bound to the exact phone number used for registration”.
- Flaky network simulations rely on the test environment’s ability to throttle traffic accurately.
- For highly regulated environments (e.g., banking), you may need to supplement autonomous data with certified test data sources.
Test Case Traceability and Requirements Mapping
Linking each test case to a requirement ensures that verification effort aligns with product specifications and supports audit trails.
Requirements Example
| REQ‑ID | Description | |
|---|---|---|
| REQ‑OTP‑01 | System shall send a 6‑digit numeric OTP numeric range 1000000. | |
| REQ‑OTP‑02 | OTP must be valid for exactly 120 seconds after generation. | |
| REQ‑03 | OTP shall be bound to the user request REQ‑OTP‑04 | System shall send a 6‑digit numeric OTP to the user's registered phone number or email upon request. |
| REQ‑OTP‑02 | OTP shall expire after a configurable time window (default 120 s). | |
| REQ‑OTP‑03 | OTP shall be usable only once used successfully. | |
| REQ‑OTP‑04 | System shall limit OTP generation requests to N per minute per user to prevent abuse. | |
| REQ‑OTP‑05 | System shall reject OTP attempts with incorrect format, length, or non‑numeric characters. | |
| REQ‑OTP‑06 | System shall provide clear, accessible error messages for OTP failures. | |
| REQ‑OTP‑07 | System shall support OTP delivery via SMS, email, push, and voice channels. | |
| REQ‑OTP‑08 | System shall allow users to resend OTP up to M times before temporary lockout. | |
| REQ‑OTP‑09 | System shall log OTP request, success, and failure events for security auditing. | |
| REQ‑OTP‑10 | System shall ensure OTP is tied to the exact user identifier (phone/email) that requested it. |
Traceability Table (excerpt)
| Test Case ID | Covered REQ‑IDs | Notes |
|---|---|---|
| OTP‑POS‑01 | REQ‑OTP‑01, REQ‑OTP‑02, REQ‑OTP‑03 | Valid code within expiry, single use |
| OTP‑NEG‑01 | REQ‑OTP‑05 | Incorrect numeric code |
| OTP‑NEG‑05 | REQ‑OTP‑02 | Expired code |
| OTP‑NEG‑06 | REQ‑OTP‑03 | Replay attempt |
| OTP‑NEG‑07 | REQ‑OTP‑04 | Rate‑limit enforcement |
| OTP‑EDG‑09 | REQ‑OTP‑07 | Fallback when SMS fails |
| OTP‑EDG‑10 | REQ‑OTP‑10 | Session binding verification |
| OTP‑POS‑07 | REQ‑OTP‑01, REQ‑OTP‑06 | Autocomplete accessibility |
Maintain this table in a version‑controlled spreadsheet or a test management tool (e.g., Zephyr, TestRail). When a requirement changes, you can instantly see which test cases need review.
Practical Checklist for OTP Verification Testing
Use this checklist before signing off a release:
- [ ] Flow diagram – OTP request → delivery → input → validation → post‑action is documented.
- [ ] Positive cases – At least one case per delivery channel (SMS, email, push, voice) with correct code, within expiry, single use.
- [ ] Negative cases – Cover invalid format, length, empty field, expired code, replay, rate‑limit, and channel‑specific failures.
- [ ] Edge/boundary cases – Test minimum/maximum OTP length, configurable expiry, resend limits, leading zeros, spaces, voice‑to‑text, and fallback mechanisms.
- [ ] Data setup – Test phone numbers/emails are isolated, mock OTP service is controllable, clock manipulation is available.
- [ ] Automation readiness – Each case has clear, imperative steps; locators are stable; test data is parameterized.
- [ ] Accessibility – Error messages are announced by screen readers; input fields have proper labels; contrast meets WCAG AA.
- [ ] Security – No OTP leakage in logs, URLs, or toast messages; rate limiting and replay protection are enforced.
- [ ] Logging & monitoring – All OTP events (request, success, failure) are written to audit logs with timestamps and user IDs.
- [ ] Regression scripts – Appium (Android) and Playwright (Web) scripts generated from manual cases are stored in version control and run on every CI build.
- [ ] Exploratory validation – Run a SUSATest session with all personas; verify that no new crash, ANR, or unhandled error appears.
If any item is unchecked, investigate and update the test suite before promoting the build.
Takeaways and Next Steps
Writing effective test cases for OTP verification is not merely about checking “correct code → success”. It requires a deep understanding of the entire verification lifecycle, disciplined case anatomy, and a blend of positive, negative, and edge scenarios that reflect real‑world usage and attack vectors.
- Start with a flow diagram – This anchors your test design and prevents gaps.
- Follow the ATDD‑style template (ID, title, preconditions, steps, data, expected result, postconditions, priority, traceability).
- Prioritize using impact/likelihood – Focus early automation on P0/P1 cases that guard core functionality and security.
- Leverage automation for repeatability – Use Appium or Playwright for the bulk of regression, but keep manual exploratory sessions for UX and accessibility validation.
- Integrate autonomous tools like SUSATest – They surface hidden race conditions, resend abuse, and accessibility friction that manual scripts may miss.
- Maintain traceability – Map each test to a requirement; update the matrix whenever the spec evolves.
- Apply the checklist – Treat it as a gate before each release candidate.
By combining carefully crafted test cases with smart, persona‑driven exploration, you achieve both depth and breadth in OTP verification coverage, reducing the risk of production‑facing failures and strengthening user trust in your authentication mechanisms.
---
*End of guide.*
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free