Last reviewed against current Android Developers and Firebase documentation.
Push notifications are one of the few features where the code can be perfect and the feature still fails. Delivery depends on a permission the user may never have granted, a channel they may have muted, whether the app was in the foreground, and whether the device was asleep. None of that appears in a unit test.
So notification testing is not "did a message arrive". It is a set of states you visit on purpose: permission granted, denied and dismissed; app open, backgrounded and closed; channel enabled and muted; the notification tapped from a cold start and from a warm one.
Quick answer
- Notifications are off by default on a fresh install on Android 13 (API level 33) and higher until the user grants the permission.
- Three permission outcomes matter: allow, don't allow, and dismiss. Dismissing changes nothing.
- "Don't allow" blocks every channel, not just the newest one — so test what your app does next, not only that nothing appears.
- Channel importance drives intrusiveness on Android 8.0+;
setPriority()applies to Android 7.1 and earlier. - Delivery timing is not a guarantee. Firebase documents normal-priority messages being delayed in Doze and high priority being attempted immediately; neither promises instant arrival.
What a notification test should actually verify
Four questions, in order. Most broken notification features fail at one of them, and each has a different fix.
- Could the user enable notifications at all? Permission granted, channel not muted, app-level notifications on.
- Was the message sent and received? Server-side send, device-side receipt, no duplicate.
- Was it displayed as intended? Title, body, icon, grouping, timing.
- Did tapping it land in the right place? Correct screen, correct content, sane back behaviour after a cold start.
Testing only the second question is the most common mistake: the notification arrives, the feature is declared working, and the tap opens the wrong screen.
Permission behaviour, and why the Android version changes the test
Android 13 (API level 33) and higher supports a runtime permission for sending notifications: POST_NOTIFICATIONS. It applies to notifications that are not exempt, including those from foreground services. The user has three possible actions, each with a documented consequence:
| User action | Documented result |
|---|---|
| Allow | Your app can send notifications. |
| Don't allow | Your app cannot send notifications unless it qualifies for an exemption. All channels are blocked — like turning off all notifications for your app in system settings. |
| Swipe the dialog away | The permission state does not change. The user neither granted nor denied it. |
Two behaviours follow that are easy to miss in testing.
New installs start with notifications off. On Android 13 or higher, a newly installed app's notifications are off by default; the app must request the permission and receive it. A tester who installs fresh and immediately expects a notification is testing an impossible state.
When the dialog appears depends on your target SDK. Targeting Android 13 or higher, the app controls when the dialog is shown. Targeting 12L (API level 32) or lower, the system shows it the first time the app starts an activity after creating a channel — usually at startup. That difference decides whether your "explain why we ask" screen ever appears.
Updates are pre-granted, with conditions. The system pre-grants the permission to eligible apps when a device upgrades to Android 13 or higher, with no prompt. Eligibility requires an existing channel and that notifications were not explicitly disabled on a device running 12L or lower — a prior denial persists after the upgrade.
Two exemptions are worth knowing so you do not chase a non-bug: media session notifications are exempt, and apps configured to self-manage phone calls do not need the permission to post CallStyle notifications.
Simulating permission states without resetting the device
Google documents ADB commands that put an app into the exact permission states you need — faster than resetting a device, and the only way to reproduce upgrade paths.
# App newly installed on Android 13 or higher adb shell pm revoke PACKAGE_NAME android.permission.POST_NOTIFICATIONS adb shell pm clear-permission-flags PACKAGE_NAME \ android.permission.POST_NOTIFICATIONS user-set adb shell pm clear-permission-flags PACKAGE_NAME \ android.permission.POST_NOTIFICATIONS user-fixed
The same page documents variants for "user kept notifications enabled on 12L then upgraded" and "user disabled notifications on 12L then upgraded". Run all three to cover the states a real upgrade produces, which a fresh install never will.
Channels, importance, and user-disabled notifications
From Android 8.0 onward, a notification belongs to a channel, and channel importance determines how intrusive it is. The older setPriority() value applies to Android 7.1 and earlier.
In testing, the channel is a user-facing control panel you do not own:
- Channels appear in the app's system settings. Google notes the channel is displayed on the App info screen when the user first runs the app.
- A user can mute one channel and keep others. Test one muted channel: the message should not appear, and your app should not treat that as an error.
- Changing a channel's importance in code later does not override what the user chose. Set it once and respect it.
Also test the app-level switch: notifications off for the whole app, then on again.
Foreground, background, and app-closed
The same message can produce three different results depending on app state. Each is a separate row in your test record:
| App state | What to check | Typical failure |
|---|---|---|
| Foreground | In-app indication instead of, or as well as, a drawer notification | Duplicate: banner plus system notification |
| Background | Notification appears; open screen updates on tap | Tap opens a stale screen |
| Closed | Notification appears; tap starts the app cleanly | Crash or blank screen on cold start |
Test the closed state both ways: swiped from recents, and force-stopped. One of them is how users report "the notification opens a white screen".
Tapping a notification: destination and deep links
A notification tap is an entry point, so test it like one:
- Correct destination and back behaviour. The tap lands on the relevant content; back goes somewhere sensible rather than exiting the app.
- Cold-start parity. The same tap from a closed app produces the same destination as from a warm one.
- Stale content. Open a notification for an item since deleted or completed; the app should degrade gracefully.
- Multiple notifications. Tap them in reverse order and confirm each opens its own content.
If your app cannot deep link to a screen, record that rather than reporting a defect — a notification opening the home screen may be intended.
Timing, duplicates, and retries
This is where expectations most often exceed what the platform promises.
Firebase Cloud Messaging documents two delivery priorities. Normal priority is the default: delivered immediately when the device is not sleeping, but possibly delayed in Doze to conserve battery. High priority is for messages that display a user-visible notification or need prompt delivery; FCM attempts immediate delivery and may wake a sleeping device, and Google advises reserving it for genuinely time-sensitive content.
What that means for testing:
- Do not assert "instant". Assert a defensible expectation — "arrives in the same session", "arrives after the device wakes" — and record what happened.
- Test the sleeping device. Leave it idle long enough to enter Doze, then send a normal-priority message. This is the delay your users see.
- Test duplicates and reconnects. Send the same message twice and confirm one notification per event; then use airplane mode, trigger an event, restore the connection, and check the result is not a burst of late notifications.
If your app does not use Firebase Cloud Messaging
Message priority, token handling and FCM's deprioritisation behaviour do not apply. The platform-level checks still do — permission, channels, importance, foreground/background/closed states, tap destination, duplicates. Run the same scenarios against your provider's documentation rather than assuming FCM's priority model transfers.
Why one device is not a notification test
Two phones on the same Android version are not the same environment. Manufacturers add their own power-management rules and notification controls, and those change when — or whether — a background message arrives. A notification that works on your development device is evidence about that device.
At minimum cover a device on your minimum supported version, one on a current version, one from a different manufacturer, and one clean install with no prior permission state. The wider device-matrix logic is covered in choosing minSdk and testing across devices.
Troubleshooting: symptom, cause, what to do
| Symptom | Likely cause | Check next |
|---|---|---|
| No notification on a fresh install | Permission never granted; off by default on Android 13+ | Request the permission, retry, confirm the prompt appeared |
| Nothing after "don't allow" | Documented: all channels blocked | Not a bug — check your app explains this state |
| Some users, never others | Channel muted, app notifications off, or vendor power rules | Ask the tester for the channel state |
| Arrives late, often after the screen wakes | Normal-priority message delayed in Doze | Confirm the priority matches the urgency you need |
| Two notifications for one event | Duplicate send, or in-app display plus system notification | Log send and display separately |
| Tap opens the wrong screen, or crashes | Deep link target wrong, stale data, or state assumed present | Repeat the tap from a force-stopped app |
Pre-release notification checklist
- Permission: requested in context with an explanation; tested with allow, don't allow and dismiss.
- Upgrade paths: pre-grant behaviour verified, including a device where notifications were disabled.
- Channels: each channel tested unmuted and muted; app-level switch tested off and on.
- States: foreground, background, swiped from recents, force-stopped.
- Tap: destination, back behaviour, cold-start parity, deleted content.
- Timing and duplicates: sleeping device tested, priority justified, same event sent twice.
- Coverage: minimum version, current version, another manufacturer, one clean install.
- Record: device, Android version, app build and permission state for every result.
When something fails on a specific device, the bug report template lists the fields that make it reproducible. For which notification problems testers should report during a closed test, see what to record during a 14-day test.
Common mistakes
Testing only the happy path. Allow, background, tap, done. The denied and muted states are where users actually live.
Assuming a fresh install behaves like your device. Your device carries accumulated permission state. Use the ADB commands or a clean device.
Treating delivery delay as a bug. Doze is documented behaviour. Decide what you require, then test against that.
Declaring reliability after one device. A closed test proves the flows on the devices in it — nothing more.
Frequently asked questions
Why do notifications not appear on a new install?
On Android 13 or higher, a newly installed app's notifications are off by default. The app cannot send them until it requests the permission and the user grants it.
What happens if the user swipes the permission dialog away?
Nothing changes. Google states the permission state does not change when the dialog is dismissed without a choice, so the app is neither allowed nor denied — and should handle that third case explicitly.
Should notifications always arrive instantly?
No such guarantee exists. Firebase documents normal-priority messages being delivered immediately when the device is not sleeping but possibly delayed in Doze, and high-priority messages being attempted immediately. Measure the behaviour you need rather than assume zero delay.
Does a closed test prove notifications work on all devices?
No. It proves the flows on the devices and Android versions in that test. Vendor power-management and notification controls differ, which is why the checklist asks for a device from a different manufacturer.
Conclusion
Notification testing is mostly a matter of visiting states on purpose: grant, deny, dismiss. Mute a channel. Send from all three app states. Tap from a cold start. Let the device sleep. Send the same message twice.
Do that on more than one device, and record what you saw rather than what you expected — instead of shipping a feature that worked on your phone and quietly failed for everyone who tapped "Don't allow".
If you need real people installing and using your build across different devices and Android versions, our team runs Google Play closed tests with progress you can watch. You can see how the 12 testers service works whenever it is useful.
Official sources
- Android Developers — Notification runtime permission
- Android Developers — Create a notification
- Android Developers — Notification channels
- Android Developers — Time-sensitive notifications
- Firebase — Set and manage Android message priority
Notification permission behaviour and delivery rules change with Android and Firebase releases. Verify current details in the documentation linked above before relying on them for a live release.