How to Test SMS OTP Verification Without a Real Phone Number
If your app sends one-time passwords by SMS, sooner or later you need to test the whole flow: the user types a phone number, your backend sends a code, the user enters it. Using your own phone for every test run is slow,
If your app sends one-time passwords by SMS, sooner or later you need to test the whole flow: the user types a phone number, your backend sends a code, the user enters it. Using your own phone for every test run is slow, burns through your SMS budget, and puts your personal number into test databases. Here are four practical ways to test SMS OTP verification without a real phone, from fully mocked to fully real.
1. Mock the SMS provider in unit tests
The fastest option: don't send anything. Wrap your SMS provider behind an interface and swap in a fake during tests.
import re
class SmsSender:
def send(self, to: str, body: str) -> None: ...
class FakeSmsSender(SmsSender):
def __init__(self):
self.outbox = []
def send(self, to, body):
self.outbox.append((to, body))
def test_signup_sends_code():
sms = FakeSmsSender()
signup(phone="+15550100", sms=sms)
to, body = sms.outbox[-1]
assert to == "+15550100"
assert re.search(r"\b\d{6}\b", body)
Good for: unit tests and CI. Misses: formatting problems, carrier filtering, delivery delays.
2. Use your provider's test mode
Most providers have a sandbox. Firebase Authentication lets you register fictional test phone numbers with a fixed code in the console (Authentication → Sign-in method → Phone → Phone numbers for testing); no SMS is sent and no quota is used. Twilio offers test credentials and "magic" numbers that simulate success and error responses for API calls without delivering real messages.
Good for: integration tests against the real SDK. Misses: what actually happens on a real network.
3. Use a temporary public number for end-to-end checks
Before a launch, or when a user reports "I never got the code", you want a real SMS on a real network. A free temporary number service such as Temp SMS shows incoming messages for public numbers in several countries on a web page, with no account required.
A typical manual check:
- Pick a number from the country you are testing, e.g. a US temporary number or a Canada receive SMS number.
- Enter it in your staging sign-up form.
- Open the number's page and confirm the message arrives, how long it took, and that the text renders correctly (sender ID, encoding, link previews).
This catches problems mocks never will: country-specific sender ID rules, Unicode characters turning into ?, messages over 160 characters splitting, or a carrier silently filtering your template.
Important: the messages on these numbers are public. Only use them for test accounts, never for real user data, admin accounts or anything protected by 2FA.
4. Use a dedicated private virtual number
For automated end-to-end tests that need real SMS, rent a private virtual number from your SMS provider and read incoming messages through its webhook or API. It costs a little each month, but messages are private and your test can assert on them programmatically.
Which approach when?
| Goal | Best option |
|---|---|
| Fast feedback in CI | Mock the sender |
| Test the real SDK without cost | Provider test mode / test numbers |
| Check real delivery in a country before launch | Temporary public number |
| Automated real-network E2E tests | Private virtual number with webhook |
Checklist for your SMS OTP flow
- Codes expire (5–10 minutes is typical) and are single-use
- Rate-limit code requests per number and per IP
- Accept common input formats: with or without +, spaces and dashes
- Message under 160 GSM-7 characters so it isn't split
- Clear sender name and app name in the text
- A "resend code" button with a cooldown
- Test at least one number per country you launch in
FAQ
Can I test SMS verification for free?
Yes. Mocks and provider test numbers cost nothing, and free temporary numbers let you check real delivery without buying a SIM.
Why does my OTP SMS arrive in one country but not another?
Carriers apply different rules: some require registered sender IDs or templates, and some filter messages that look like spam. Test with a real number in each target country.
Is it safe to use public temporary numbers?
For throwaway test accounts, yes. Never use them for production admin accounts or real customer data, because anyone can read the messages.
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.