How to Test Push Notifications on Android (Complete Guide)

Push notifications are a direct line from an app to its users. When they work, they drive engagement, convey timely information, and can even be a revenue channel. When they fail, users miss critical

June 18, 2026 · 17 min read · How-To Guides

Why Push Notification Testing Matters

Push notifications are a direct line from an app to its users. When they work, they drive engagement, convey timely information, and can even be a revenue channel. When they fail, users miss critical alerts, perceive the app as unreliable, and may disable notifications altogether—or uninstall the app.

Impact on User Experience

A notification that appears late, shows garbled text, or lacks a usable action creates friction. Users expect immediacy; a delay of even a few seconds can cause them to act on stale information (e.g., a flash‑sale alert that arrives after the sale ends). Poorly formatted notifications break accessibility expectations: TalkBack users rely on concise, descriptive content; missing content labels or low contrast make the notification unreadable.

Business Risks

Missed notifications translate to lost opportunities. For e‑commerce, a failed cart‑abandonment reminder can mean a dropped sale. For finance apps, a delayed fraud alert can expose users to risk and increase liability. From a compliance standpoint, regulations such as GDPR require that personal data not be inadvertently exposed in notification content; a bug that leaks a token or email in the notification tray can trigger fines and damage brand reputation.

Compliance and Security

Push notifications travel through Firebase Cloud Messaging (FCM) or alternative push services. The payload is often encrypted in transit, but the notification itself is displayed by the system UI. If the app places personally identifiable information (PII) in the title or text fields, that data becomes visible on the lock screen or in the notification shade, violating privacy expectations. Testing must therefore verify that no sensitive data leaks and that the app honors user‑granted permission states (e.g., notification disabled, Do Not Disturb).

---

Test Matrix for Push Notifications

A comprehensive matrix helps you ensure that every relevant dimension is exercised. Below is a table that groups test cases by category, description, expected outcome, and pass/fail criteria.

IDCategoryScenarioDescriptionExpected ResultPass/Fail Criteria
H1Happy PathForeground deliveryApp is in foreground, FCM sends a simple data‑only message.App receives message via FirebaseMessagingService.onMessageReceived and updates UI accordingly.UI reflects new data within 2 seconds; no crash.
H2Happy PathBackground notificationApp is in background, FCM sends a notification payload with title, text, and icon.System shows notification in shade; tapping opens the designated Activity.Notification appears with correct title/text/icon; tapping launches correct screen; back stack behaves as defined.
H3Happy PathAction buttonNotification includes two action buttons (e.g., “Reply”, “Dismiss”).Tapping each button triggers the corresponding BroadcastReceiver or Service.Correct receiver logs action; UI updates if needed; no ANR.
H4Error PathInvalid payloadFCM sends a message with malformed JSON (missing to field).FCM discards message; app receives no callback.No crash; log shows FCM error; app state unchanged.
H5Error PathExceeding size limitPayload > 4 KB (FCM limit).FCM rejects message; device receives nothing.No notification appears; logs show MessagingError.
H6Error PathMissing channel (Android 8.0+)Notification posted without a valid notification channel ID.Notification is silently dropped (post‑Oreo).No notification shade entry; log warns about missing channel.
H7Edge CaseDoze modeDevice is idle, Doze activated; FCM sends high‑priority message.System delivers notification within a short grace period; app can show heads‑up if allowed.Notification appears within ≤ 30 seconds; no excessive battery drain.
H8Edge CaseBattery optimization whitelist exemption removedUser disables exemption for the app; app attempts to post a notification while in background.Notification still delivered but may be delayed; app must handle deferral gracefully.Notification eventually appears; no crash; app logs deferral if using WorkManager.
H9Edge CaseMultiple channelsApp defines three channels (Promotions, Reminders, Alerts) with different importance levels.Each channel respects its importance setting (e.g., Alerts heads‑up, Promotions silent).Verify importance via NotificationManager.getNotificationChannel; observe UI behavior.
H10Edge CaseNotification groupingApp sends five messages with same group key; system should collapse them.Notification shade shows a single grouped entry; expanding reveals individual messages.Group summary displays correct count; expanding shows each child.
H11AccessibilityTalkBack navigationNotification posted; user explores with TalkBack.TalkBack reads title, text, and action labels correctly.No missing contentDescription; spoken text matches visible content.
H12AccessibilityContrastNotification uses low‑contrast text on icon background.Text must meet WCAG AA contrast ratio (≥ 4.5:1).Use automated contrast checker; flag if ratio < 4.5.
H13Security/PrivacySensitive data in payloadFCM message includes user email in title field.Email must not appear in notification shade (should be filtered or omitted).Verify notification text does not contain email; ensure app strips PII before posting.
H14Security/PrivacyReplay attack simulationCapture a valid FCM token and re‑send old notification payload.App should detect stale nonce or timestamp and ignore replay.No duplicate UI update; log shows rejection.
H15Security/PrivacyPermission revoked mid‑sessionUser disables notifications in system settings while app is running.Subsequent FCM messages result in no notification; app should handle gracefully.No notification appears; app logs REMOTE_MESSAGE_RECEIVED but no posting.
H16LocalizationRight‑to‑left languageDevice locale set to Arabic; notification includes mixed LTR/RTL text.Layout respects RTL direction; punctuation positioned correctly.Verify layout direction via View.getLayoutDirection; visual inspection.
H17PerformanceRapid burstApp sends 50 notifications in 2 seconds via FCM.System batches or throttles; UI remains responsive.No dropped frames; ANR watchdog does not trigger.
H18FallbackFCM token refreshSimulate token expiration; FCM returns new token.App registers new token with backend; continues to receive messages.Backend receives updated token; no gap in message delivery.

*How to use the matrix*: Treat each row as a test case. Automate the verifiable assertions (UI state, logs, backend calls) and run them on a matrix of devices (different API levels, OEM skins, battery‑optimization settings).

---

Manual Testing Approach

Manual testing remains valuable for exploratory checks, especially when validating edge cases that depend on device state or user interaction. Below is a step‑by‑step procedure you can follow on a physical device or emulator.

Environment Setup

  1. Enable Developer Options – Tap *Settings → About phone → Build number* seven times.
  2. USB Debugging – Turn on *Developer options → USB debugging*.
  3. Install the app – Use adb install -r app.apk to ensure a clean install.
  4. Grant notification permission – On Android 13+, go to *Settings → Apps → → Notifications* and enable the channel(s) you plan to test.
  5. Clear existing notifications – Swipe away all notifications or run adb shell cmd notification cancelall.

Using ADB to Send Notifications

You can simulate FCM downstream messages without a backend by using the adb shell cmd notification command or by pushing a raw payload via firebase CLI.

Simple notification via ADB


adb shell cmd notification post -S bigtext \
  -t 'Test Title' \
  --es 'msg' 'Hello from ADB' \
  com.example.myapp

Sending a data‑only message (requires FCM)

If you have a test server that can call the FCM HTTP v1 API, issue:


curl -X POST -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
     -H "Content-Type: application/json" \
     -d '{
           "message": {
             "token": "<DEVICE_FCM_TOKEN>",
             "data": {
               "score": "850",
               "time": "2:45"
             }
           }
         }' \
     https://fcm.googleapis.com/v1/projects/<PROJECT_ID>/messages:send

Retrieve the device token with:


adb shell cmd notification list | grep com.example.myapp

or via FirebaseInstanceId.getInstance().getToken() in a debug build.

Verifying Notification Appearance

  1. Shade inspection – Pull down the shade and confirm title, text, icon, and any action buttons are present.
  2. Heads‑up vs silent – For high‑importance channels, verify a heads‑up popup appears; for low importance, ensure no interruption.
  3. Lock screen visibility – Power off the device, wake it, and check whether the notification shows on the lock screen (based on setVisibility).
  4. Icon adaptation – Ensure the app’s monochrome icon (required for Android 13+) appears correctly when the device theme is dark.

Interacting with the Notification

Checking Foreground/Background Behavior

App StateExpected Notification Handling
Foreground (visible)FirebaseMessagingService.onMessageReceived receives data payload; you may choose to show a custom dialog instead of a system notification.
Background (not visible)System shows notification based on payload; tapping behavior defined in setContentIntent.
Force‑stoppedNo notification should appear (unless using a high‑priority FCM with content_available=true on iOS—irrelevant for Android).

To test background, press Home or switch to another app before sending the FCM message.

Using Android Studio Logcat

Filter logs for your app’s tag and FCM:


adb logcat | grep -i fcm

Look for:

Exploratory Checks

---

Automated Approaches

Automation provides repeatability and scalability. Below are techniques ranging from unit tests to cloud‑based device farms, plus a mention of how autonomous, persona‑driven exploration can surface issues that scripted tests miss.

Unit Testing Notification‑Related Logic

Test the construction of NotificationCompat.Builder and any helper methods that decide channel importance or filter payloads.


@Test
public void buildNotification_setsCorrectChannel() {
    NotificationCompat.Builder builder = NotificationHelper.createReminderNotification(context);
    Notification notif = builder.build();
    assertEquals("reminder_channel", notif.getChannelId());
}

Use Robolectric to run Android‑framework tests on the JVM without an emulator or device.

Instrumented Tests with Espresso/UIAutomator

Espresso excels at verifying UI after a notification tap; UIAutomator can interact with the shade and system dialogs.

Example: Espresso test for notification tap


@Rule
public ActivityTestRule<MainActivity> activityRule =
        new ActivityTestRule<>(MainActivity.class);

@Test
public void notificationTap_opensDetailScreen() {
    // Trigger a local notification via a helper method
    NotificationHelper.fireTestNotification(getInstrumentation().getTargetContext());

    // Open the shade and click the notification
    UiDevice device = UiDevice.getInstance(getInstrumentation());
    device.openNotification();
    // Wait for the notification to appear
    UiObject2 notif = device.wait(Until.findObject(By.text("Test Title")), 5000);
    assertNotNull(notif);
    notif.click();

    // Verify the detail Activity is launched
    intended(hasComponent(DetailActivity.class.getName()));
}

UIAutomator for shade interactions


@Test
public void headsUpNotification_isDisplayed() {
    UiDevice device = UiDevice.getInstance(getInstrumentation());
    // Send a high‑priority notification via adb or FCM from test code
    NotificationHelper.sendHighPriorityNotification(getInstrumentation().getTargetContext());

    // Wait for heads‑up popup
    UiObject2 headsUp = device.wait(Until.findObject(By.clazz("android.widget.TextView")
                                                            .text("Test Title")), 5000);
    assertNotNull(headsUp);
    // Verify it’s visible (not just in shade)
    assertTrue(headsUp.isVisible());
}

Run these tests on a matrix of devices via Gradle:


./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.numShards=4

Using Firebase Test Lab

Test Lab lets you execute your instrumentation suite on a wide range of physical and virtual devices in Google’s cloud.

  1. Upload APK and test APK – Build both with ./gradlew assembleDebug assembleDebugAndroidTest.
  2. Create a test matrix – In the Firebase console, select devices (e.g., Pixel 4 API 33, Samsung S22 API 33, low‑end device API 28).
  3. Trigger

gcloud firebase test android run \
  --type instrumentation \
  --app app-debug.apk \
  --test app-debug-test.apk \
  --device model=Pixel4,version=33,locale=en,orientation=portrait  \
  --device model=SamsungGalaxyS22,version=33,locale=en,orientation=portrait

Test Lab automatically collects logs, screenshots, and performance metrics, making it easy to spot device‑specific regressions (e.g., a notification channel that fails on certain OEM skins).

Leveraging SUSA for Autonomous, Persona‑Driven Exploration

SUSA explores the app without pre‑written scripts, simulating distinct user personas (curious, impatient, novice, adversarial, elderly, accessibility‑focused, power user, etc.). When you point SUSA at an APK or a web‑view wrapper, it will:

Because SUSA builds a session‑level memory of visited screens and dead ends, it learns which notification‑related flows are flaky (e.g., a notification that only appears after a specific sequence of deep links). After a run, SUSA can export Appium (Android) or Playwright (Web) regression scripts that capture the exact steps to reproduce a discovered bug.

Running SUSA locally


pip install susatest-agent
susatest run --apk path/to/app.apk \
             --personas curious impatient elderly \
             --fcmsimulator \
             --output ./susa-report

The --fcmsimulator flag tells SUSA to use its built‑in FCM mock, which can send varied payloads (different channels, action buttons, data‑only messages) while logging the app’s reaction. The resulting report includes:

You can then feed the failing scenarios into your CI pipeline as additional instrumented tests.

---

Edge Cases that Appear Only in Production

Some bugs surface only when the app runs under real‑world constraints: fluctuating networks, aggressive power‑saving policies, or heterogeneous device fleets. Below is a detailed look at those scenarios and how to test for them.

Network Conditions

FCM relies on a persistent HTTPS connection to Google’s servers. If the device switches between Wi‑Fi, cellular, or loses connectivity, the downstream message may be delayed or queued.

Test approach

Doze Mode and App Standby

Starting with Marshmallow, Doze defers background network access and delays FCM high‑priority messages until a maintenance window. App Standby further restricts apps the user hasn’t interacted with recently.

Test approach

Battery Optimization Whitelist

OEMs often add aggressive battery‑saving layers that can stop background services or alarm managers.

Test approach

Multiple Notification Channels

Apps targeting API 26+ must create channels; each channel can have its own importance, sound, vibration, and lock‑screen visibility. Misconfiguration leads to notifications being silently dropped or overly intrusive.

Test approach

Payload Size Limits

FCM imposes a 4 KB limit on the total payload (including keys). Exceeding this results in silent drop.

Test approach

Notification Grouping and Bundling

Starting with Android 9, the system can group notifications by setGroupKey. Misusing group keys can cause unexpected collapsing or expanding behavior.

Test approach

Accessibility Considerations

TalkBack users rely on spoken feedback; notification accessibility hinges on proper contentDescription and concise text.

Test approach

Security and Privacy

Sensitive data must never appear in the notification text. Additionally, replay attacks can be mitigated by including a nonce or timestamp that the backend validates.

Test approach

---

Integrating Push Notification Tests into CI/CD

Automated tests gain real value when they run on every change, providing fast feedback on regressions. Below is a practical way to embed push‑notification verification into a Git‑centric workflow.

Triggering Tests on Pull Request

Configure your CI system (GitHub Actions, GitLab CI, Bitbucket Pipelines) to run the instrumentation suite on push‑request events.

GitHub Actions example


name: Push Notification Tests

on:
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          distribution: temurin
          java-version: '17'
      - name: Grant execute permission for Gradlew
        run: chmod +x gradlew
      - name: Download Firebase Test Lab credentials
        run: |
          echo "${{ secrets.FIREBASE_SERVICE_ACCOUNT }}" > firebase.json
          gcloud auth activate-service-account --key-file firebase.json
      - name: Run instrumentation on Test Lab
        run: |
          ./gradlew assembleDebug assembleDebugAndroidTest
          gcloud firebase test android run \
            --type instrumentation \
            --app app/build/outputs/apk/debug/app-debug.apk \
            --test app/build/outputs/apk/androidTest/debug/app-debug-test.apk \
            --device model=Pixel4,version=33,locale=en,orientation=portrait \
            --timeout 2m

This workflow builds the APKs, authenticates with Firebase Test Lab, and executes the test matrix on a Pixel 4 emulator. Adjust the device list to cover your target market.

Publishing Results

Test Lab automatically stores results in a Firebase Storage bucket. You can link those results to the PR via a comment:


gcloud firebase test android result bucket --gsutil \
  gs://test-lab-results/<project-id>/<timestamp>/ \
  cp results.xml .

Then use the GitHub API to post a comment with a link to the HTML report.

Flaky Test Mitigation

Push‑notification tests can be flaky due to timing variances. Apply these patterns:

  1. Retry wrapper – In your test framework, wrap flaky assertions in a retry loop with exponential backoff (max 3 attempts).
  2. Deterministic FCM mock – For unit and instrumentation tests, replace the real FCM downstream with a local mock server (e.g., using MockWebServer). This removes network jitter.
  3. Time‑budget assertions – Instead of asserting exact delivery time, assert a range (e.g., “notification appears within 5‑30 seconds after sending”).

---

Checklist for Push Notification Testing

Use this concise list before marking a release as ready.

AreaItemVerification Method
PermissionNotification permission granted (runtime & system)adb shell pm grant android.permission.POST_NOTIFICATIONS
ChannelAll required channels created with correct importance, sound, vibrationadb shell cmd notification listchannels
ForegroundData‑only messages handled in onMessageReceived without showing a notification (if desired)Logcat check for handler execution; no shade entry
BackgroundNotification appears with correct title, text, icon, and action intentsShade inspection + tap test
Action ButtonsEach button triggers the intended BroadcastReceiver/ServiceLog or UI change after button press
Heads‑upHigh‑importance notification shows heads‑up popup (if not suppressed)Visual inspection on unlocked device
Lock‑screenVisibility matches setVisibility (public/private/secret)Lock device, wake, observe notification
AccessibilityTalkBack reads title, text, and actions; contrast ≥ 4.5:1TalkBack navigation + Accessibility Scanner
GroupingNotifications with same groupKey collapse; expanding shows allSend grouped notifications; verify shade behavior
Doze / StandbyNotification delivered within expected window after exiting idle statesForce Doze/Standby, measure latency
Battery OptimizationNotification still delivered when exemption removed (may be delayed)Disable exemption, send notification, observe delay
Payload SizeMessages > 4 KB are rejected server‑side; no silent drop on deviceSend oversized payload, check server logs & device logcat
LocalizationRTL layout respected; text not truncatedSwitch language to Arabic/Hebrew, inspect notification
SecurityNo PII in title/text; replay protection in placeInspect notification content; resend old payload, ensure ignored
PerformanceNo ANR or excessive CPU when receiving burst of 50 notificationsStress test with adb shell cmd notification post … in a loop, monitor adb logcat for ANR
Fallback Token RefreshApp registers new token with backend after FCM token rotationSimulate token expiration, verify backend receives updated token
CI IntegrationTests run on PR; results visible; failures block mergeCheck CI pipeline logs and PR comments

---

Closing Takeaways

Push notifications are a high‑impact, high‑risk surface. A disciplined testing strategy blends:

By treating push notifications as a first‑class citizen in your test suite—not an afterthought—you protect user trust, maintain engagement metrics, and avoid costly post‑release incidents. Keep the checklist handy, iterate on your matrix as you add new notification features, and let both scripted and exploratory testing complement each other. Your users will notice the difference in reliability, and your engineering team will spend less time firefighting noisy alerts in production.

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