How to Test Address Autocomplete on Android (Complete Guide)

Address autocomplete is a tiny UI widget that can make or break a user’s first impression. When it works, a user types a few characters and instantly sees a relevant suggestion, taps it, and moves on.

March 25, 2026 · 19 min read · How-To Guides

Why Address Autocomplete Deserves Focused Testing

Address autocomplete is a tiny UI widget that can make or break a user’s first impression. When it works, a user types a few characters and instantly sees a relevant suggestion, taps it, and moves on. When it fails, the user may abandon a form, enter an incorrect address, or trigger a crash that propagates to downstream services (shipping, tax calculation, fraud detection).

In production, autocomplete failures are often hidden behind device‑specific quirks: different IMEs, varying network latency, locale‑specific address formats, or accessibility services that intercept input events. A script that only checks the happy path on a single emulator will miss these issues, while a manual tester can only sample a fraction of the possible combinations.

Because the widget touches several layers—UI, input method, network, data storage, and sometimes native code—testing it requires a matrix that spans functional correctness, error handling, performance, accessibility, and privacy. The following sections give you a complete, practical guide to cover all of those angles on Android.

---

Common Ways Autocomplete Breaks in the Wild

Before we define what to test, it helps to see the patterns that repeatedly surface in bug reports and crash logs.

Failure CategoryTypical SymptomRoot Cause
Network glitchesSuggestion list never appears or shows stale dataTimeout handling missing, no retry, or UI not updated on error
IME interferenceKeyboard hides the suggestion popup, or typing jumpsPopup anchored to wrong window, missing adjustResize/adjustPan
Locale mismatchSuggestions show US ZIP codes for a French addressGeocoding service called with wrong locale or regionCode
Empty or malformed responseApp crashes with NullPointerException when parsing JSONNo guard against empty predictions array
Duplicate suggestionsSame address appears multiple times in the listBackend returns duplicates, UI does not deduplicate
Accessibility blockTalkBack reads nothing when focus moves to listMissing contentDescription or importantForAccessibility flags
Security leakSuggestion log contains full address in plaintext logsDebug logging enabled in release build
Privacy violationUser’s typed query sent to third‑party analytics without consentAnalytics SDK attached to autocomplete view without opt‑out
Performance jankUI freezes for >200 ms after each keystrokeHeavy work done on main thread (e.g., JSON parsing)
Orientation changeSuggestion list disappears after rotationViewModel not retained, or popup not re‑anchored

These categories form the backbone of our test matrix. Each one can be exercised manually, automated, or discovered by an autonomous explorer that simulates real user personas.

---

Test Matrix for Address Autocomplete

The table below lists the dimensions you should cover. For each dimension we note the test type (manual, automated, persona‑driven), the expected outcome, and a sample test case. Use this as a checklist when you build your test suite.

DimensionSub‑areaTest TypeExpected OutcomeSample Test Case
Happy pathBasic suggestionAutomated (Espresso)List appears after ≥2 chars, correct orderingType “1600 Amph” → see “1600 Amphitheatre Pkwy, Mountain View, CA”
Multiple languagesManualSuggestions respect device localeSet device to fr-FR, type “1600 Am” → see French‑formatted address
SelectionAutomated (UI Automator)Tapping a suggestion fills the field and closes popupTap first item → field text equals suggestion, popup gone
Error handlingNetwork timeoutAutomated (MockWebServer)Show error toast, keep existing text, allow retryDelay response 10 s → toast “Unable to load suggestions”, field unchanged
Empty responseAutomated (Espresso)No crash, show hint “No results”Mock server returns {} → hint visible, list hidden
Malformed JSONAutomated (Robolectric)Graceful fallback, log errorServer returns plain text → app does not crash, logs warning
IME & UISoft keyboard overlayManualPopup not covered by keyboard, scrolls if neededUse Gboard, long text → popup appears above keyboard
Hardware keyboardManualSame behavior as soft keyboardConnect USB‑KB, type → suggestions appear
Configuration changeAutomated (ActivityScenario)Popup persists or re‑appears correctlyRotate device while list shown → list still visible
AccessibilityTalkBack navigationManual (TalkBack enabled)Each list item announces address and roleFocus moves to list → TalkBack reads “1600 Amphitheatre Pkwy, Mountain View, CA, button”
ContrastAutomated (Accessibility Scanner)Minimum 4.5:1 for text vs backgroundCheck suggestion item colors
Touch target sizeManual≥48 dp heightMeasure with layout inspector
Security / PrivacyNo debug loggingAutomated (Logcat capture)No address string in logcat release buildType address, filter logs for autocomplete → no matches
Opt‑out respectedManual (with analytics SDK)If user disables analytics, query not sentDisable analytics in settings, type address, verify network call absent
Secure transmissionAutomated (Network security config)All autocomplete calls use HTTPSUse network_security_config.xml with cleartextTrafficPermitted="false"
PerformanceLatency <200 msAutomated (Benchmark)95th percentile of suggestion latency ≤200 msRun Macrobenchmark with varied network throttling
Memory stableAutomated (LeakCanary)No leak after 50 open/close cyclesOpen/close popup 50×, assert no retained activity
Edge CasesDuplicate suppressionManualList shows unique suggestions onlyBackend returns same address twice → UI shows one entry
Special charactersManualHandles apostrophes, hyphens, UnicodeType “O’Connor St.” → suggestions appear correctly
Very long inputManualUI does not overflow or crashPaste 500‑char string → suggestions truncated or error shown gracefully
Fast typingManualNo missed characters, list updates appropriatelyType “123 Main St” at 10 cps → each intermediate state shows correct list
Network switchManualGraceful handling when moving from Wi‑Fi to cellularStart on Wi‑Fi, disable it mid‑type, continue on cellular → suggestions still appear
SIM‑based country detectionManualWhen SIM country differs from locale, suggestions prefer SIMInsert US SIM, set device locale to de-DE, type “1600” → US addresses prioritized

---

Manual Testing – Step‑by‑Step Walkthrough

A disciplined manual session helps you catch subtle UI glitches that automated checks may overlook. Follow this procedure on a physical device (or a well‑configured emulator) for each build you want to validate.

  1. Prepare the device
  1. Launch the screen containing the autocomplete field
  1. Happy‑path validation
  1. Error‑path validation
  1. IME and keyboard tests
  1. Accessibility checks
  1. Security & privacy sniffing
  1. Performance observation
  1. Edge‑case scenarios
  1. Final sign‑off

When you finish, you should have a clear pass/fail verdict for each matrix cell. Document any deviations and create tickets for the development team.

---

Automated Testing on Android

Automated checks give you confidence that regressions are caught early and that you can run the matrix on every CI build. Below are the most effective techniques for address autocomplete, grouped by the layer they target.

Unit‑level Logic (ViewModel / UseCase)

If your autocomplete logic lives in a ViewModel (e.g., calling a repository that wraps the Places API), write plain JUnit tests with MockK or Mockito.


// AddressViewModelTest.kt
class AddressViewModelTest {

    private val repositoryMock = mockk<AddressRepository>()
    private val viewModel = AddressViewModel(repositoryMock)

    @Test
    fun `shows suggestions when repository returns non‑empty list`() {
        // arrange
        val fakeResponse = listOf(
            Suggestion("1600 Amphitheatre Pkwy, Mountain View, CA"),
            Suggestion("1600 Pennsylvania Ave NW, Washington, DC")
        )
        coEvery { repositoryMock.getSuggestions("1600") } returns fakeResponse

        // act
        viewModel.query("1600")

        // assert
        assertEquals(fakeResponse, viewModel.suggestions.getOrElse { emptyList() })
    }

    @Test
    fun `handles empty response gracefully`() {
        coEvery { repositoryMock.getSuggestions("xyz") } returns emptyList()
        viewModel.query("xyz")
        assertTrue(viewModel.suggestions.isNullOrEmpty())
        assertTrue(viewModel.errorMessage.isNotEmpty()) // UI shows hint
    }
}

*Why this matters*: Unit tests catch logic errors (e.g., faulty sorting, missing null checks) without needing an emulator, giving you fast feedback.

Instrumented UI Tests (Espresso)

Espresso excels at validating the interaction between the UI and the autocomplete dropdown. Use IdlingResource to wait for asynchronous network calls.


// AddressAutocompleteTest.kt
@RunWith(AndroidJUnit4::class)
class AddressAutocompleteTest {

    private val mockWebServer = MockWebServer()

    @Before
    fun setUp() {
        mockWebServer.start()
        // Inject the mock base URL into your app via Dependency Injection or BuildConfig
        ActivityScenario.launch<AddressActivity>()
    }

    @After
    fun tearDown() {
        mockWebServer.shutdown()
    }

    @Test
    fun `displays suggestions after two characters`() {
        // enqueue a delayed response to simulate latency
        mockWebServer.enqueue(
            MockResponse()
                .setResponseCode(200)
                .setBody("""{
                    "predictions": [
                        {"description": "1600 Amphitheatre Pkwy, Mountain View, CA"},
                        {"description": "1600 Amherst St, Buffalo, NY"}
                    ]
                }""")
                .setBodyEncoding("utf-8")
                .setHeader("Content-Type", "application/json")
                .setBodyDelay(2, TimeUnit.SECONDS)
        )

        onView(withId(R.id.address_input))
            .perform(typeText("1600"), closeSoftKeyboard())

        // Wait for the list to appear
        onView(withId(R.id.suggestion_list))
            .check(matches(isDisplayed()))

        onView(withText("1600 Amphitheatre Pkwy, Mountain View, CA"))
            .check(matches(isDisplayed()))
    }

    @Test
    fun `shows error toast on network failure`() {
        mockWebServer.enqueue(
            MockResponse()
                .setResponseCode(504)
                .setBodyDelay(5, TimeUnit.SECONDS)
        )

        onView(withId(R.id.address_input))
            .perform(typeText("1600"), closeSoftKeyboard())

        onView(withText(containsString("Unable to load")))
            .inRoot(ToastMatcher())
            .check(matches(isDisplayed()))
    }
}

Key points

UI Automator for System‑Level Interactions

When you need to test behavior that crosses app boundaries (e.g., the suggestion popup being obscured by the system status bar or a floating chat head), UI Automator is the right tool.


// AddressPopupUiAutomatorTest.java
@RunWith(AndroidJUnit4.class)
public class AddressPopupUiAutomatorTest {

    private UiDevice device;

    @Before
    public void setUp() {
        device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        // launch the app
        Context ctx = Registry.getInstrumentation().getTargetContext();
        Intent intent = ctx.getPackageManager()
                .getLaunchIntentForPackage(ctx.getPackageName());
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        ctx.startActivity(intent);
    }

    @Test
    public void suggestionListNotCoveredByKeyboard() {
        // open the keyboard
        device.pressKeyCode(KeyEvent.KEYCODE_SHIFT_LEFT);
        device.pressKeyCode(KeyEvent.KEYCODE_SPACE);
        // type a few chars
        for (char c : "1600".toCharArray()) {
            device.pressKeyCode(KeyEvent.getKeyCode(String.valueOf(c)));
        }

        // get bounds of the suggestion list UI element
        UiObject2 list = device.findObject(By.clazz("android.widget.ListView"));
        assertNotNull(list);
        Rect listBounds = list.getVisibleBounds();

        // get bounds of the soft keyboard (approx via window frame)
        UiObject2 window = device.findObject(By.clazz("android.widget.PopupWindow"));
        Rect keyboardBounds = window != null ? window.getVisibleBounds() : new Rect();

        // ensure the bottom of the list is above the top of the keyboard
        assertTrue(listBounds.bottom < keyboardBounds.top);
    }
}

This test catches the frequent bug where the popup appears under the keyboard on certain device configurations (especially tablets with navigation bars).

Benchmark Tests for Performance

Use the Macrobenchmark library to measure end‑to‑end latency from keystroke to suggestion display.


// AddressAutocompleteBenchmark.kt
@get:Rule
val benchmarkRule = MacrobenchmarkRule()

@Test
fun `measure suggestion latency`() {
    benchmarkRule.measureRepeated(
        packageName = "com.example.app",
        metrics = listOf(FrameTimingMetric()),
        iterations = 5,
        setup = {
            // start at the address screen
            startActivityAndWait()
        }
    ) {
        // simulate typing two chars
        val input = device.findObject(By.res("com.example.app", "address_input"))
        input.setText("16")
        // wait a fixed time for suggestions to appear (you can also wait for a view)
        Thread.sleep(250)
    }
}

The resulting CSV report gives you the 50th, 90th, and 95th percentile frame times; you can assert that the 95th percentile stays below 200 ms.

Accessibility Test Automation

Leverage Accessibility Test Framework (ATF) from Google or the axe-android runner to scan for WCAG violations.


# Install the tester
pip install accessibility-test-framework-for-android

# Run on a connected device
atf run --app com.example.app --package com.example.app --test-target android.support.test.runner.AndroidJUnitRunner

The tool will output violations such as missing contentDescription, insufficient contrast, or touch targets smaller than 48 dp.

Security / Privacy Checks with Network Security Config

Ensure your app’s network_security_config.xml enforces HTTPS for autocomplete endpoints.


<!-- res/xml/network_security_config.xml -->
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">maps.googleapis.com</domain>
        <domain includeSubdomains="true">api.example.com</domain>
    </domain-config>
</network-security-config>

Then add a unit test that asserts the config is present:


@Test
fun `network security config disallows cleartext`() {
    val xml = Resources.getSystem().getXml(R.xml.network_security_config)
    val domainConfig = xml.nextTag() // <domain-config>
    assertEquals("false", domainConfig.getAttributeValue(null, "cleartextTrafficPermitted"))
}

If you use a debugging proxy (e.g., Charles) in a debug build, make sure the config is overridden only for that build type.

---

Tooling & Libraries Cheat‑Sheet

CategoryTool / LibraryPrimary UseExample Command / Snippet
Mock networkMockWebServer (OkHttp)Simulate latency, errors, payload shapesmockWebServer.enqueue(new MockResponse().setBodyDelay(2, TimeUnit.SECONDS))
Dependency injectionHilt / DroidSwap real repository for fakes in tests@BindValue @JvmField val fakeRepo = mockk()
UI testingEspresso + IdlingResourceAssert on UI after async callsidlingResource = object : IdlingResource { … }
System UIUI AutomatorTest overlay, keyboard, navigation bar interactionsUiDevice.getInstance(...)
PerformanceMacrobenchmarkMeasure frame timing, startup, memory@get:Rule val benchmarkRule = MacrobenchmarkRule()
AccessibilityAccessibility Test Framework (ATF)Automated WCAG scansatf run --app com.example.app …
SecurityNetwork Security Config + adb logcatEnforce HTTPS, detect accidental clear‑text
Leak detectionLeakCanary (debug)Catch activity/fragment leaks after popup open/closeLeakCanary.install(app)
Analytics opt‑outFirebase Analytics setAnalyticsCollectionEnabled(false)Verify no data sent when disabledFirebaseAnalytics.getInstance(context).setAnalyticsCollectionEnabled(false)

Keep this table handy when you set up a new test module; most of the entries are available via Maven Central and add minimal overhead to your APK.

---

Edge Cases That Only Surface in Production

Even the most exhaustive lab matrix can miss issues that appear only when real users interact with the app under unpredictable conditions. Below are the most common production‑only gotchas and how to surface them deliberately.

1. Locale‑Specific Address Formats

Some countries require the postal code *before* the city (e.g., Japan), others use hyphens in postal codes (UK), and a few have multiple address lines. If your autocomplete view assumes a strict “street, city, state, ZIP” pattern, you’ll see truncated or malformed suggestions.

How to test

2. Carrier‑Dependent Country Detection

Many geocoding APIs prefer the SIM’s country code over the device locale when determining result bias. A user roaming abroad may get irrelevant suggestions.

How to test

If your app does not expose a way to override this bias, consider adding a setting that lets the user lock the region.

3. IME‑Specific Inline Prediction

Certain IMEs (Gboard, SwiftKey, Samsung Keyboard) show their own inline suggestions above the soft keyboard. If your popup is anchored to the window’s top, it may clash with these inline bars, causing visual overlap or input lag.

How to test

4. Background Data Restrictions

Android’s battery‑optimization may restrict background network access, causing the autocomplete service to fail after the app has been idle for a while.

How to test

5. Network Switch Mid‑Typed

Users often move from Wi‑Fi to cellular while typing. A sudden change in latency or DNS resolution can cause stale suggestions or duplicate requests.

How to test

6. Accessibility Service Interference

Services like TalkBack, Switch Control, or third‑party screen readers can intercept key events, causing double‑typing or missed characters.

How to test

7. Data‑Quota Exhaustion

On metered connections, the OS may block further network requests after a quota is hit. Autocomplete should degrade gracefully rather than crash or show a blank spinner forever.

How to test

By deliberately reproducing these conditions in a controlled environment (using adb, tc, or a custom test harness), you turn “production‑only” bugs into reproducible failures you can fix before release.

---

Concise Checklist for Release

Before you tag a build as ready for production, run through this short list. Each item can be verified with a combination of manual spot‑checks and automated CI jobs.

✅ ItemHow to Verify
Happy‑path suggestion appearsEspresso test: type 2 chars → list displayed
Network error handled gracefullyMockWebServer 504 → toast, field unchanged
Empty response shows hintMockWebServer {} → hint visible, no crash
Selection fills field and closes popupUI Automator tap → field text = suggestion, popup gone
TalkBack reads each list itemEnable TalkBack, navigate list → announcement includes full address
Contrast ≥ 4.5:1Run ATF or Accessibility Scanner → no contrast failures
Touch target ≥ 48 dpMeasure with layout inspector → height/width ≥ 48dp
No address string in logcat (release)`adb logcatgrep autocomplete` → no matches
Analytics opt‑out respectedDisable analytics → network sniffer shows no query calls
All autocomplete calls use HTTPSInspect network_security_config.xmlcleartextTrafficPermitted="false"
95th‑percentile latency ≤200 msMacrobenchmark → frame timing report
No memory leak after 50 open/close cyclesLeakCanary → leak‑free after repeated popup open/close
Duplicate suggestions suppressedBackend returns same entry twice → UI shows one
Special characters handledType “O’Connor St.” → suggestions appear, no crash
Long input does not crashPaste 500‑char string → graceful error or truncation
Fast typing (10 cps) keeps syncType rapidly → each intermediate state shows correct list
Network switch mid‑type recoversToggle Wi‑Fi/Cellular while typing → suggestions continue
SIM‑country bias respected (if desired)Insert foreign SIM, keep locale → results biased to SIM
Background restriction does not block callsEnable background restriction → suggestions still work (or show cached)
Metered connection shows fallbackSet metered + 429 response → user‑friendly message, no crash

If any item fails, create a ticket, fix the root cause, and re‑run the checklist before proceeding.

---

Autonomous, Persona‑Driven Exploration – Where Scripts Fall Short

Traditional test suites excel at verifying *what you told them to check*. They are less effective at discovering *what you never imagined* a user might do. This is where an autonomous QA platform that simulates real user personas adds value.

How Persona‑Driven Search Works

A persona‑driven explorer builds a behavioral model for each user type (e.g., “impatient teen”, “elderly novice”, “power user”, “adversarial tester”). The model dictates:

The explorer then drives the actual Android UI (via UiAutomator or Accessibility Service) using those profiles, without any pre‑written test script. It records every screen visited, every action taken, and any anomaly (crash, ANR, dead button, accessibility violation, unexpected network call, etc.). Over successive runs it builds a knowledge base of *dead ends*—UI states that lead nowhere—and avoids re‑exploring them, making each session more efficient.

What It Finds That Scripts Miss

Issue ClassWhy Scripts Overlook ItPersona‑Driven Detection
Hidden dead‑end screens (e.g., a modal that blocks the suggestion list)Scripts follow a happy‑path flow; they never open the modal unless explicitly told.An “impatient” persona may tap randomly, hit the modal, and notice the list never appears.
Race condition between IME and popupScripts use a fixed delay; they don’t vary timing.A “power‑user” persona types at 12 cps, triggering a popup that appears under the keyboard on a specific device‑IME combo.
Accessibility trap (e.g., suggestion list not focusable)Scripts rarely enable TalkBack unless the test case explicitly requires it.A “novice with low vision” persona turns on TalkBack, tries to navigate the list, and finds it inaccessible.
Privacy leak via loggingScripts check for a specific tag; they may not notice a new logging statement added in a refactor.An “adversarial” persona deliberately enables logcat capture and watches for any address string after each keystroke.
Localized address formatting bugScripts often test only en-US.A “world traveler” persona switches locale frequently, enters addresses in multiple scripts, and spots mis‑ordered components.
Network‑quota throttling reactionScripts usually run on unmetered Wi‑Fi.A “budget‑conscious” persona enables metered network, hits a quota, and observes the app’s fallback behavior.

Because the explorer does not rely on pre‑written assertions, it surfaces *behavioral* bugs that are often only caught after a real user complains in the wild.

Integrating SUSA for Address Autocomplete

SUSA (SUSATest) is an autonomous QA agent that you can point at an APK or a web URL. It automatically:

  1. Installs the app on a fleet of real or emulated devices.
  2. Selects a persona set (you can enable all eight built‑in personas or curate a subset).
  3. Drives the UI, exercising every clickable element, text field, and gesture.
  4. Detects crashes, ANRs, dead buttons, WCAG violations, security

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