Test cases for OTP verification
Updated 2026-11-13 · 6 min read
Thirty cases for a delivered login code, including exact expiry boundaries and concurrent verification. Explicit fixture rules make resend and lockout results checkable.
How to answer in an interview
Ask whether this is login, contact verification or approval of a transaction. Clarify code length, expiry, retry limits and what resend does to an older code. Lead with a valid verification, then show how you would test expiry on the server and prevent a code from verifying the wrong account.
Scope and test data
Assume a delivered login code, not an authenticator-app TOTP. The example contract is six ASCII digits, a 180-second lifetime from server issuance, five wrong attempts per challenge and a 30-second resend cooldown. A successful resend invalidates the previous code; five wrong attempts lock that challenge. These are example product decisions, not OTP standards. Use a fake account such as [email protected] and a delivery stub; a fixture code such as 012345 must exist only in that stub. Do not send test messages to arbitrary phone numbers. OWASP recommends short-lived, single-use OTPs and controls against guessing; it does not prescribe this example policy.
The 30 cases below are a test design, not an execution report. Replace the example rules with approved requirements before recording pass or fail. Performance budgets and supported device versions must be agreed before execution.
Verification and input
| ID | Category | Test case | Expected result |
|---|---|---|---|
| O01 | Functional | Enter the current six-digit code before expiry | Login completes for the account bound to the challenge |
| O02 | Functional | Enter a fixture code beginning with zero | All six characters are preserved and verification succeeds |
| O03 | Functional | Paste the complete code into the first input | All digits populate in order and one verification can be submitted |
| O04 | Negative | Submit an empty value | Required message appears and no login is granted |
| O05 | Boundary | Submit five digits and then seven digits | Both are rejected without verifying a truncated value |
| O06 | Negative | Enter letters, spaces or non-ASCII digit characters | Input is rejected with the six-digit format requirement |
| O07 | Negative | Submit a well-formed but incorrect code | Verification fails and one wrong attempt is recorded |
| O08 | Functional | Correct the code after one failed attempt | Current valid code succeeds while attempts remain |
Time, resend and races
| ID | Category | Test case | Expected result |
|---|---|---|---|
| O09 | Boundary | Submit at server age 179 seconds with delivery latency controlled | Verification succeeds before the 180-second expiry |
| O10 | Boundary | Submit at server age exactly 180 seconds | Code is expired and no login is granted |
| O11 | Security | Set the device clock backwards and submit an expired code | Server expiry still rejects the code |
| O12 | Boundary | Request resend at 29 seconds after issuance | No new delivery occurs and the cooldown is explained |
| O13 | Boundary | Request resend at 30 seconds | One new challenge code is delivered and the old code is invalidated |
| O14 | Negative | After successful resend, submit the previous code | Old code fails even if its original expiry has not passed |
| O15 | Functional | Submit the newly resent code | Login succeeds before the new code expires |
| O16 | Negative | Simulate delivery-provider failure during resend | User sees retry guidance; the existing challenge is not silently replaced with an unusable one |
| O17 | Security | Send two concurrent verification requests for one correct code | At most one request consumes the challenge; no second independent login is granted |
| O18 | Security | Reuse a code after successful verification | Used challenge cannot grant another login |
Abuse protection and recovery
| ID | Category | Test case | Expected result |
|---|---|---|---|
| O19 | Boundary | Make five wrong attempts, then submit the right code | Challenge remains locked and cannot authenticate |
| O20 | Security | Refresh or open another tab after exhausting attempts | Server-side attempt count remains exhausted |
| O21 | Security | Resend repeatedly after locking a challenge | Account-level abuse controls prevent an unlimited fresh guessing budget |
| O22 | Security | Submit account A code with account B challenge identifier | Neither account is authenticated by the mismatched pair |
| O23 | Security | Use a contact-verification code on the login endpoint | Purpose mismatch is rejected |
| O24 | Security | Inspect test logs, URLs and analytics payloads | Raw codes are absent from those records |
| O25 | Negative | Lose the network while verification is in flight | UI offers recovery and checks session state before asking for another code |
| O26 | Functional | Change the destination before requesting a new code | Old challenge cannot verify the replacement destination |
Usability and delivery quality
| ID | Category | Test case | Expected result |
|---|---|---|---|
| O27 | UI | Use keyboard and screen reader to enter a code and read an error | Input purpose, focus and error are perceivable without relying on colour |
| O28 | UI | Delete a middle digit in a segmented input | Focus and remaining digits permit correction without silently reordering the code |
| O29 | Performance | Measure stub delivery and verification separately at agreed peak load | Both meet their separate budgets; delivery delay is not hidden inside verification timing |
| O30 | Compatibility | Repeat paste, leading-zero and expiry cases on supported mobile and desktop browsers | Same verification outcome; keyboard and paste behavior remain usable |
Evidence and prioritisation
Prioritise O01, O10, O14, O17 and O22: they probe success, expiry, replacement, concurrency and account binding. Record issuance time, server verification time, challenge identifier and outcome without retaining the raw code. A common mistake is checking only the countdown animation; it is the server decision that matters. For a follow-up about TOTP, explain that clock windows and seed enrolment need a separate suite. See the login cases for the surrounding session flow.
Downloads
Quick answers
Is every OTP six digits?
No. Length and character set belong to the product contract; six digits is only the fixture used here.
Does resend always invalidate the old code?
Not universally. This suite assumes it does; agree the replacement rule and test it on the server.
Sources
Want a project you can show in interviews?
The portfolio project kit walks you through testing a deliberately buggy app with Selenium or Playwright and API tests, then explaining it. The app itself is free.
