How to Test Ratings And Reviews on Android (Complete Guide)

Ratings and reviews are the primary signal users rely on when deciding whether to install an app from Google Play. A high average score drives organic installs, while a low score can trigger a steep d

April 21, 2026 · 20 min read · How-To Guides

Why Ratings and Reviews Matter for Android Apps

Ratings and reviews are the primary signal users rely on when deciding whether to install an app from Google Play. A high average score drives organic installs, while a low score can trigger a steep drop‑off in conversion. Beyond acquisition, the review text contains actionable feedback about crashes, usability problems, missing features, and privacy concerns. When a rating‑related flow breaks—such as the in‑app review prompt failing to appear, the submit button being disabled, or the review text being lost—users experience friction that often leads to negative public feedback and a lower star rating. Therefore, verifying that the ratings and reviews subsystem works correctly under realistic conditions is a quality gate that directly impacts business metrics.

Core Components of the Ratings & Reviews Flow

Most Android apps expose ratings and reviews through one of three mechanisms:

  1. Google Play In‑App Review API – launches a modal dialog managed by Play Services, allowing users to write and submit a review without leaving the app.
  2. Custom web view – loads a hosted web page (often a Firebase Dynamic Link or a proprietary server) that mimics the Play Store review UI.
  3. Deep link to Play Store – uses an intent with market://details?id= to open the store listing; the user then manually taps “Write a review”.

Each path shares common UI elements: a rating bar (usually 1‑5 stars), an optional text field for comments, a submit button, and handling of dialog results (success, cancellation, error). Underlying the UI are network calls to Google’s review endpoints, token authentication, and occasional fallback logic when Play Services is unavailable. Understanding these components helps you design tests that cover both the UI layer and the service layer.

Test Matrix: Happy Path, Error Paths, Edge Cases, Accessibility, Security/Privacy

CategoryTest IDDescriptionExpected ResultNotes
Happy PathHP‑1Launch review flow from app bar → select 5 stars → add comment → tap Submit → receive success toastReview submitted, toast shown, rating updated locallyVerify Play Services connection
Happy PathHP‑2Launch review flow → select 3 stars → leave comment blank → tap Submit → review submitted without commentReview submitted, no comment storedSome apps allow empty comment
Error PathER‑1No internet connection → launch review flow → attempt submitError dialog shown, no rating change, app does not crashHandle NetworkOnMainThreadException gracefully
Error PathER‑2Play Services outdated → launch review flow → dialog fails to loadFallback to web view or Play Store deep link, no crashVerify fallback logic
Error PathER‑3Rating bar tapped rapidly 10 times → submitOnly final rating recorded, no duplicate submissionsCheck debounce logic
Edge CaseED‑1Very long comment (5000 characters) → submitComment truncated or rejected per server limit, appropriate error shownVerify server‑side limit handling
Edge CaseED‑2Emoji‑only comment → submitEmoji rendered correctly in review listTest Unicode handling
Edge CaseED‑3User changes orientation mid‑flowUI state preserved, rating and comment retainedUse onSaveInstanceState
Edge CaseED‑4Low memory device → launch review flowUI renders, no OOM crash, possible low‑resolution assetsTest with adb shell am set-debug-app
AccessibilityAC‑1TalkBack enabled → navigate rating barEach star announces “star, button, not selected” / “selected”Verify content descriptions
AccessibilityAC‑2Switch Control → submit button reachableSubmit can be activated via switchCheck focus order
AccessibilityAC‑3High contrast font size → text fields legibleNo clipping, readable contrast ratio ≥ 4.5:1Use Android Studio’s Accessibility Scanner
Security/PrivacySE‑1Malicious comment with SQL injection attempt → submitInput sanitized, no server error, no data leakageValidate backend sanitization
Security/PrivacySE‑2Review flow launched from background service without UINo unintended permission prompts, no background network call without user consentEnsure foreground service restriction
Security/PrivacySE‑3Rating request intercepted via MITM (using adb reverse)App detects certificate pinning failure, shows error, does not submitTest with mitmproxy and custom CA

This matrix gives you a concrete checklist that can be turned into test cases for both manual and automated execution. Each row isolates a single risk factor, making it easier to trace failures back to root causes.

Manual Testing Approach: Step‑by‑Step Guide

  1. Prepare the test device
  1. Validate Play Services availability
  1. Execute the happy‑path flow
  1. Inject error conditions
  1. Exercise edge cases
  1. Run accessibility checks
  1. Perform security/privacy spot checks
  1. Clean up

Following this manual routine ensures you touch every cell in the test matrix and observe the app’s behavior under realistic variations.

Automated Testing on Android: Tools and Frameworks

Automating ratings and reviews validation requires interacting with system dialogs that may reside outside your app’s process. The most reliable approach combines UIAutomator (for cross‑app interactions) with Espresso (for in‑app UI) and, when needed, the Google Play In‑App Review API test library.

Tool Comparison

ToolScopeStrengthsLimitationsTypical Use for Reviews
EspressoSame‑process UIFast, reliable synchronization, rich assertionsCannot interact with system dialogs or other appsValidate rating bar, comment field, submit button inside your activity
UIAutomatorCross‑process UICan launch intents, interact with system dialogs, access notification shadeSlower, less fluent API, requires UiDevice handlingTrigger In‑App Review dialog via intent, handle Play Store deep link, dismiss system dialogs
Firebase Test LabCloud‑based device farmRuns on real devices, API level matrix, video captureRequires project setup, per‑minute costExecute UIAutomator test suites across multiple device configurations
ADB Monkey / adb shell monkeyStress testingGenerates random UI events, good for stabilityNo assertions, blind to specific flowsGenerate edge‑case input (rapid taps) to uncover race conditions
Play Core Testing LibraryIn‑App Review API mockProvides FakeReviewManager for unit‑test‑style verificationLimited to API calls, no UIVerify that your code calls ReviewManager.launchReviewFlow with correct parameters

A robust automated suite typically layers Espresso for the in‑app portion, UIAutomator to launch and dismiss the review dialog, and optionally Firebase Test Lab to run on a matrix of real devices.

Setting Up UIAutomator for Review Dialogs

Add the dependency in your build.gradle (module):


androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
androidTestUtil 'androidx.test:orchestrator:1.4.2'

Create a test class:


@RunWith(AndroidJUnit4.class)
public class ReviewFlowTest {

    private UiDevice device;

    @Before
    public void setUp() {
        device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        // Start the app from launcher
        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
        final Intent intent = context.getPackageManager()
                .getLaunchIntentForPackage(context.getPackageName());
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);
        device.wait(Until.hasObject(By.pkg(context.getPackageName()).depth(0)), 5000);
    }

    @Test
    public void testInAppReviewHappyPath() throws Exception {
        // Navigate to the screen that shows the rate button
        OnView(withId(R.id.btn_rate)).perform(click());

        // Expect the Play Store review dialog to appear (system UI)
        // The dialog title contains "Rate this app"
        UiObject reviewDialog = device.findObject(new UiSelector()
                .textContains("Rate this app")
                .className(android.widget.FrameLayout.class.getName()));
        assertTrue("Review dialog did not appear", reviewDialog.waitForExists(3000));

        // Set rating to 4 stars (assuming 5-star bar with IDs)
        for (int i = 1; i <= 4; i++) {
            UiObject star = device.findObject(new UiSelector()
                    .descriptionContains("star")
                    .index(i - 1));
            star.click();
        }

        // Enter comment
        UiObject commentField = device.findObject(new UiSelector()
                .className(android.widget.EditText.class.getName()));
        .class.getName()));
        commentField.setText("Great app!");

        // Click submit
        UiObject submitBtn = device.findObject(new UiSelector()
                .text("Submit")
                .className(android.widget.Button.class.getName()));
        submitBtn.click();

        // Verify success toast
        UiObject toast = device.findObject(new UiSelector()
                .className(android.widget.Toast.class.getName())
                .textContains("Thanks"));
        assertTrue("Success toast not shown", toast.waitForExists(3000));
    }
}

Explanation of key steps

Espresso Test for In‑App UI

If your app uses a custom review screen (not the system dialog), Espresso suffices:


@RunWith(AndroidJUnit4.class)
public class CustomReviewScreenTest {

    @Rule
    public ActivityTestRule<ReviewActivity> activityRule =
            new ActivityTestRule<>(ReviewActivity.class, true, false);

    @Test
    public void submitReview_withValidData_showsSuccess() {
        activityRule.launchActivity(new Intent());

        onView(withId(R.id.ratingBar)).perform(setRating(4));
        onView(withId(R.id.editComment)).perform(typeView("Works well"));
        onView(withId(R.id.btnSubmit)).perform(click());

        onView(withId(R.id.txtSuccess))
                .check(matches(withText("Thank you for your feedback!")));
    }
}

Here setRating is a custom ViewAction that iterates over the rating bar’s stars and calls perform(click()) on each.

Running on Firebase Test Lab

Package your UIAutomator tests:


./gradlew connectedAndroidTest   # generates APKs in app/build/outputs/apk/androidTest/debug

Upload to Test Lab:


gcloud firebase test android run \
    --type instrumentation \
    --app app-debug.apk \
    --test app-debug-androidTest.apk \
    --device model=Pixel3,version=30,locale=en,orientation=portrait \
    --device model=PixelXL,version=28,locale=en,orientation=landscape

Test Lab will execute the tests on real hardware, capture logs, screenshots, and video, giving you confidence that the review flow works across diverse device configurations.

Code Samples: Instrumented Tests with Espresso/UIAutomator

Below is a complete, copy‑paste‑ready Gradle module that demonstrates both Espresso and UIAutomator tests for a typical ratings and reviews flow.

build.gradle (module)


plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdk 34

    defaultConfig {
        applicationId "com.example.reviewdemo"
        minSdk 21
        targetSdk 34
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
                    'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation "androidx.core:core-ktx:1.13.0"
    implementation "androidx.appcompat:appcompat:1.7.0"
    implementation "com.google.android.material:material:1.12.0"
    implementation "androidx.constraintlayout:constraintlayout:2.1.4"

    // Testing
    androidTestImplementation "androidx.test:core:1.5.0"
    androidTestImplementation "androidx.test.ext:junit:1.1.5"
    androidTestImplementation "androidx.test.espresso:espresso-core:3.5.1"
    androidTestImplementation "androidx.test.uiautomator:uiautomator:2.2.0"
    androidTestUtil "androidx.test:orchestrator:1.4.2"
}

Espresso Test (CustomReviewScreenTest.kt)


package com.example.reviewdemo

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class CustomReviewScreenTest {

    @Rule
    @JvmField
    val activityRule = ActivityScenarioRule(ReviewActivity::class.java)

    @Test
    fun `submit review with valid data shows success`() {
        // Assume RatingBar uses the default Material rating bar
        onView(withId(R.id.ratingBar))
                .perform(actionWithId(R.id.ratingBar, setRating(4f))) // custom action below

        onView(withId(R.id.editComment))
                .perform(typeText("Great app!"), closeSoftKeyboard())

        onView(withId(R.id.btnSubmit))
                .perform(click())

        onView(withId(R.id.txtSuccess))
                .check(matches(withText("Thanks for your rating!")))
    }

    /** Helper to set a rating on a RatingBar */
    private fun actionWithId(viewId: Int, rating: Float): ViewAction {
        return object : ViewAction {
            override fun getConstraints() = MatcherMatchers.isAssignableFrom(RatingBar::class.java)
            override fun getDescription() = "Set rating to $rating"
            override fun perform(uiController: UiController?, view: View?) {
                view as? RatingBar ?: return
                view.isIndicator = false
                view.rating = rating
            }
        }
    }
}

UIAutomator Test (ReviewFlowUiAutomatorTest.java)


package com.example.reviewdemo;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiSelector;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertTrue;

@RunWith(AndroidJUnit4.class)
public class ReviewFlowUiAutomatorTest {

    private UiDevice device;

    @Before
    public void setUp() {
        device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        // Launch app
        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
        Intent intent = context.getPackageManager()
                .getLaunchIntentForPackage(context.getPackageName());
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);
        device.wait(Until.hasObject(By.pkg(context.getPackageName()).depth(0)), 5000);
    }

    @Test
    public void testInAppReviewFallbackToPlayStore() throws Exception {
        // Trigger review flow (assumes a button with id btn_rate)
        OnView(withId(R.id.btn_rate)).perform(click());

        // Wait for either the in‑app review dialog or the Play Store activity
        UiObject reviewDialog = device.findObject(new UiSelector()
                .textContains("Rate this app")
                .className(android.widget.FrameLayout.class.getName()));
        boolean inAppShown = reviewDialog.waitForExists(3000);

        if (!inAppShown) {
            // Fallback: check that Play Store activity is in foreground
            UiObject playStore = device.findObject(new UiSelector()
                    .packageName("com.android.vending")
                    .className(android.widget.FrameLayout.class.getName()));
            assertTrue("Play Store did not open as fallback", playStore.waitForExists(5000));
        } else {
            // Proceed with in‑app review interaction (same as happy‑path test)
            // ... (rating, comment, submit) omitted for brevity
        }
    }
}

These snippets illustrate how to:

You can extend the UIAutomator test to cover error scenarios (airplane mode, outdated Play Services) by inserting adb shell svc wifi disable or installing an older com.google.android.gms APK before the test runs.

Autonomous, Persona‑Driven Exploration with SUSA

Traditional scripted tests excel at verifying known paths, but they often miss emergent issues that appear only when real users behave unpredictably. SUSA (susatest.com) addresses this gap by autonomously exploring an app using a set of modeled personas—each persona encapsulates a distinct behavior profile (e.g., “impatient” taps rapidly, “elderly” uses larger touch targets, “adversarial” attempts malformed inputs, “accessibility” relies on TalkBack, “power user” exploits shortcuts, etc.).

When you point SUSA at an APK or a web URL, it:

  1. Installs the app on a fleet of real or emulated devices.
  2. Selects a persona and drives the UI according to that persona’s policy (tap duration, scroll speed, input length, error‑recovery tolerance).
  3. Triggers the ratings and reviews flow wherever it appears—whether via a floating action button, a settings menu, or a contextual prompt after a completed task.
  4. Observes outcomes: crash logs, ANR traces, UI freezes, accessibility warnings, network failures, and unexpected state transitions.
  5. Records each explored screen as a node in a graph; subsequent runs avoid revisiting known dead ends and prioritize unexplored edges, making the exploration progressively smarter.

Because SUSA does not rely on pre‑written test cases, it can discover bugs such as:

SUSA’s output includes a PASS/FAIL verdict for each discovered flow, a video capture of the session, and a structured bug report (steps, logs, device state). Moreover, after each run it can auto‑generates Appium scripts and Playwright (Web)**—allowing you to turn the discovered by‑regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression regression

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