How to Test Biometric Login on Android (Complete Guide)
Biometric authentication has moved from a novelty to a baseline expectation for Android apps that handle sensitive data—banking, health, enterprise, or any service that stores personal identifiers. Wh
Why Biometric Login Matters on Android
Biometric authentication has moved from a novelty to a baseline expectation for Android apps that handle sensitive data—banking, health, enterprise, or any service that stores personal identifiers. When a user can unlock an app with a fingerprint or face scan, friction drops, conversion rises, and the perception of security improves.
In production, biometric login is a frequent source of regressions because the underlying framework touches multiple layers: hardware abstraction, OS‑level crypto, the Android BiometricPrompt API, and the app’s own session management. A change in any of those layers—OEM sensor firmware, a system update, a Play Services patch, or a refactor of the login flow—can cause silent failures that users experience as “the button does nothing” or “the app crashes after I place my finger.”
Testing biometric login therefore needs to verify not only that the happy path works, but also that error handling, fallback mechanisms, accessibility accommodations, and privacy guarantees remain intact across device variations and OS versions.
Understanding the Android Biometric Framework
Before writing tests, grasp the moving parts that the test suite will interact with.
BiometricPrompt (API 28+)
BiometricPrompt is the recommended, unified way to request fingerprint, face, or iris authentication. It abstracts away the deprecated FingerprintManager and provides a consistent callback interface:
onAuthenticationSucceeded– returns aCryptoObjectif you opted to use one.onAuthenticationError– fatal errors (e.g., hardware locked out).onAuthenticationFailed– non‑fatal failures (bad match).
The prompt is displayed by the system, not by your UI, which means you cannot directly manipulate the dialog; you can only observe callbacks and supply a BiometricPrompt.PromptInfo object.
FingerprintManager (deprecated)
Some legacy apps still call FingerprintManager.authenticate. On API 28+ this class simply forwards to BiometricPrompt internally, but on older devices it talks directly to the HAL. Tests that target pre‑Android 9 devices must handle both paths.
Hardware‑Backed Keystore
When you request a CryptoObject (usually a Signature or Cipher), the BiometricPrompt ties the authentication outcome to the use of a key stored in the hardware‑backed Keystore. If the key is invalidated (e.g., after too many failed attempts), subsequent crypto operations throw KeyPermanentlyInvalidatedException.
OEM Variations
Samsung, Xiaomi, OnePlus, and others expose extra callbacks (e.g., onAuthenticationHelp with vendor‑specific codes) and may show customized UI. Your test matrix must include at least one device from each major OEM family to catch vendor‑specific quirks.
Test Matrix for Biometric Login
Below is a comprehensive matrix that covers the dimensions you should verify. Each cell indicates the expected outcome; “PASS” means the app behaves correctly, “FAIL” indicates a defect.
| Category | Sub‑case | Test Action | Expected Result | Notes |
|---|---|---|---|---|
| Happy Path | Fingerprint match | Place enrolled finger on sensor | onAuthenticationSucceeded called, app proceeds to main screen, session token created | Verify that any CryptoObject is usable (e.g., signature validates). |
| Happy Path | Face match (if supported) | Look at front camera | Same as fingerprint | Only on devices with face hardware; skip otherwise. |
| Happy Path | No biometric enrolled, fallback to PIN | BiometricPrompt set to allow device credential; cancel biometric, enter PIN | onAuthenticationSucceeded via device credential, app proceeds | Confirms graceful fallback. |
| Error Path | Sensor unavailable (disabled) | Disable fingerprint in Settings, invoke login | onAuthenticationError with error code BIOMETRIC_ERROR_HW_UNAVAILABLE; app shows fallback UI | Ensure app does not crash. |
| Error Path | Too many failed attempts (lockout) | Fail 5 times with wrong finger, then try correct finger | onAuthenticationError with BIOMETRIC_ERROR_LOCKOUT; app shows lockout message, no crypto returned | Verify lockout duration matches OS policy. |
| Error Path | Canceled by user | Tap cancel button on system prompt | onAuthenticationError with BIOMETRIC_ERROR_USER_CANCELED; app returns to login screen | Check that any temporary UI is dismissed. |
| Edge Case | Rapid fire taps | Tap login button 10 times quickly | Only one BiometricPrompt shown; subsequent taps are ignored until current flow finishes | Prevents multiple overlapping prompts. |
| Edge Case | Screen rotation during prompt | Rotate device while prompt visible | Prompt remains visible, callbacks delivered correctly after rotation | Ensure activity/fragment state is preserved. |
| Edge Case | Low battery / power save mode | Enable extreme battery saver, invoke login | Prompt may be delayed or show low‑power warning; app still receives correct callback | Confirm that app does not treat delay as failure. |
| Accessibility | TalkBack enabled | Turn on TalkBack, navigate to login button, double‑tap | TalkBack reads button label, prompt announced, user can authenticate via gesture; result matches non‑accessible flow | Verify that focus returns to appropriate element after success/failure. |
| Accessibility | Font size large | Set system font to 200%, invoke login | Layout does not clip prompt title or description; all text readable | Test on smallest supported screen size. |
| Security / Privacy | Key invalidation after lockout | Trigger lockout, then attempt to use CryptoObject | Crypto operation throws KeyPermanentlyInvalidatedException; app must re‑authenticate | Ensures that compromised keys are not reused. |
| Security / Privacy | No leakage of biometric data in logs | Run login with verbose logging, inspect logcat | No raw fingerprint templates, sensor IDs, or authentication results appear in logs | Confirm that only result codes are logged. |
| Security / Privacy | Prompt hijack resistance | Overlay another app with TYPE_APPLICATION_OVERLAY while prompt active | System blocks overlay; prompt remains visible, user cannot interact with overlay | Confirms that FLAG_SECURE is effectively applied to the prompt window. |
| Regression | OS update (e.g., Android 13 → 14) | Flush device to newer API, repeat happy path | Same behavior as before; no new error codes | Run on a device farm or emulator with target API. |
| Regression | Play Services update | Update Google Play Services, repeat error paths | Vendor‑specific help codes unchanged; app still maps them correctly | Play Services may add new help messages; ensure your mapping is extensible. |
*Table 1 – Biometric login test matrix covering functional, error, edge, accessibility, and security dimensions.*
Tool Comparison
| Tool | Strengths | Limitations | Typical Use Case |
|---|---|---|---|
| Espresso + IdlingResource | Fast, runs on JVM, integrates with AndroidJUnitRunner | Cannot interact with system dialog directly; needs mocking or delegation | Unit‑style tests of view‑model logic, validation of callback handling |
| UI Automator | Can interact with system windows, including BiometricPrompt dialog | Slower, requires API 21+, flaky on some OEM builds | End‑to‑end tests that need to press system buttons (cancel, fallback) |
| AndroidX Test (FragmentScenario) | Lets you inject a fake BiometricPrompt via dependency injection | Requires refactoring to expose prompt creator; not a black‑box test | Testing fragment/view‑model in isolation, verifying crypto usage |
| Firebase Test Lab | Runs on real devices in the cloud, matrix of OS/OEM combos | Cost per minute, limited to test execution time | Broad compatibility verification across many devices |
| SUSA (SUSATest) autonomous agent | Explores app without scripts, uses persona‑driven behavior, discovers edge cases missed by manual scripts | Requires upload of APK or URL; less control over exact test steps | Continuous regression, discovery of unexpected UI states, accessibility, and security regressions |
*Table 2 – Comparison of common Android testing approaches for biometric login.*
Manual Testing Approach
A disciplined manual session complements automation by catching nuances that scripts may overlook, such as haptic feedback, timing perception, or accessibility announcements. Follow this step‑by‑step checklist on a physical device (prefer a device with enrolled biometrics).
- Prepare the device
- Enroll at least one fingerprint and, if available, a face profile.
- Disable developer options that might interfere (e.g., “Show taps”).
- Ensure the app is installed from the same build you intend to test (debug or release).
- Baseline happy path
- Launch the app, navigate to the login screen.
- Tap the biometric login button.
- Place the enrolled finger on the sensor; observe the system prompt (should show app name and icon).
- Verify that after successful authentication the app proceeds to the expected landing page and that a session token is stored (check via ADB:
adb shell run-as).cat shared_prefs/ .xml
- Fallback to device credential
- In the app settings (or via a test flag), enable “allow device credential”.
- Cancel the biometric prompt (tap the cancel button).
- Enter the device PIN/Password/pattern.
- Confirm that the app treats this as a successful login and proceeds.
- Error path – sensor disabled
- Go to Settings → Security → Fingerprint and toggle it off.
- Attempt biometric login again.
- Expect an error dialog or toast indicating that biometric hardware is unavailable, and the app should either show the fallback UI or stay on the login screen.
- Error path – lockout simulation
- Fail authentication five times using an unregistered finger.
- On the sixth attempt, use the registered finger.
- The system should present a lockout message; the app must not receive a success callback.
- After the lockout period (usually 30 seconds), retry with the registered finger and confirm success.
- Cancel behavior
- While the prompt is visible, tap the system cancel button.
- The app should receive
onAuthenticationErrorwithBIOMETRIC_ERROR_USER_CANCELEDand return to the login screen without crashing or leaving stray UI elements.
- Rapid fire test
- Spam the login button ten times in quick succession.
- Verify that only one system prompt appears and that subsequent taps are ignored until the current flow resolves (success, error, or cancel).
- Configuration change
- While the prompt is showing, rotate the device.
- Ensure the prompt stays visible and that after authentication the app correctly restores UI state (e.g., any progress bar disappears).
- Accessibility checks
- Enable TalkBack, set font size to largest, and optionally enable color inversion.
- Navigate to the login button using swipe gestures; confirm that the button is announced with a meaningful label.
- Double‑tap to activate; verify that TalkBack reads the prompt title and that after success/failure the focus returns to a logical element (e.g., the username field).
- Security observation
- With the device connected to a workstation, run
adb logcat -v timeand filter for your app’s tag. - Perform a biometric login and confirm that no raw sensor data, token values, or error details appear in the log.
- Attempt to use an overlay app (e.g., a floating chat head) while the prompt is active; the overlay should be blocked or unable to intercept touch events.
- Document findings
- For each step, note the device model, OS version, OEM, and any deviations from the expected behavior.
- Capture screenshots or screen recordings for any unexpected UI states.
Manual testing is time‑consuming but invaluable for catching issues that depend on timing, sensory feedback, or device‑specific quirks that automated scripts may not emulate faithfully.
Automated Testing Approaches
Automation provides repeatability and scalability. Below are patterns for each major testing layer, with concrete code snippets you can copy into your project.
1. Mock‑Based Unit Tests (ViewModel / UseCase)
If your architecture separates the BiometricPrompt invocation behind an interface (e.g., BiometricAuthenticator), you can unit‑test the consumer without touching the OS.
// BiometricAuthenticator.kt
interface BiometricAuthenticator {
fun authenticate(
fragment: Fragment,
callback: BiometricCallback
)
}
// FakeBiometricAuthenticator.kt
class FakeBiometricAuthenticator(
val result: Result = Result.Success
) : BiometricAuthenticator {
override fun authenticate(
fragment: Fragment,
callback: BiometricCallback
) {
// Simulate async callback after a small delay
fragment.lifecycleScope.launch {
delay(100)
when (result) {
Result.Success -> callback.onSucceeded(mockCryptoObject())
Result.Error -> callback.onError(
BiometricPrompt.ErrorCodes.BIOMETRIC_ERROR_HW_UNAVAILABLE,
"Hardware unavailable"
)
Result.Canceled -> callback.onCanceled()
}
}
}
}
// ViewModel test
@ExperimentalCoroutinesApi
class LoginViewModelTest {
private val testDispatcher = UnconfinedTestDispatcher()
private lateinit var viewModel: LoginViewModel
@Before
fun setUp() {
Dispatchers.setMain(testDispatcher)
val fakeAuth = FakeBiometricAuthenticator(Result.Success)
viewModel = LoginViewModel(fakeAuth)
}
@Test
fun `authentication success navigates to home`() = runTest {
viewModel.login()
assertTrue(viewModel.uiState.value is LoginState.Authenticated)
}
}
*Why this helps:* You verify that the ViewModel correctly interprets each callback, updates LiveData/StateFlow, and triggers navigation—all without needing a device or emulator.
2. Espresso Tests with IdlingResource
Espresso cannot directly interact with the system BiometricPrompt dialog, but you can register an IdlingResource that watches for the callback from your BiometricAuthenticator.
// BiometricIdlingResource.kt
class BiometricIdlingResource(
private val authenticator: BiometricAuthenticator
) : IdlingResource {
private var callback: IdlingResource.ResourceCallback? = null
private var isIdle = true
override fun getName() = "BiometricIdlingResource"
override fun isIdleNow(): Boolean {
return isIdle
}
override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) {
this.callback = callback
}
// Called by production code after BiometricPrompt finishes
fun onAuthenticationCompleted() {
isIdle = true
callback?.onTransitionToIdle()
}
fun onAuthenticationStarted() {
isIdle = false
}
}
// In your test
@RunWith(AndroidJUnit4::class)
class LoginEspressoTest {
private lateinit var idlingResource: BiometricIdlingResource
@Before
fun registerIdlingResource() {
val authenticator = // obtain from your DI or Activity
idlingResource = BiometricIdlingResource(authenticator)
IdlingRegistry.getInstance().register(idlingResource)
}
@Test
fun biometricLogin_success_showsHome() {
// Perform action that triggers BiometricPrompt
onView(withId(R.id.btn_biometric_login)).perform(click())
// IdlingResource will move to idle when authenticator signals completion
onView(withText("Welcome")).check(matches(isDisplayed()))
}
@After
fun unregister() {
IdlingRegistry.getInstance().remove(idlingResource)
}
}
*Key point:* The IdlingResource is notified by your production code (e.g., inside the BiometricAuthenticator implementation) when the prompt flow starts and ends. This lets Espresso wait for the asynchronous operation without sleeping.
3. UI Automator for System Dialog Interaction
When you need to validate that the system prompt appears with the correct title, icon, or that the cancel button works, UI Automator is the right choice.
@RunWith(AndroidJUnit4::class)
class BiometricUiAutomatorTest {
private val uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
@Test
fun promptShowsCorrectTitle() {
// Launch the app and trigger biometric login
val context = ApplicationProvider.getApplicationContext<Context>()
val intent = Intent(context, LoginActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
// Wait for the system dialog to appear (timeout 5 sec)
val prompt = uiDevice.wait(
Until.findObject(By.clazz("android.widget.TextView")
.textContains("Login with fingerprint")),
5000
)
assertNotNull(prompt)
// Verify the app name is in the dialog
val appName = context.getString(R.string.app_name)
assertTrue(prompt.text.contains(appName))
// Press cancel and ensure we return to the login screen
val cancelBtn = uiDevice.findObject(By.desc("Cancel"))
cancelBtn.click()
onView(withId(R.id.email_input)).check(matches(isDisplayed()))
}
}
*Considerations:* UI Automator tests are slower and can be flaky on OEM ROMs that modify the system dialog’s resource IDs. Use them sparingly—primarily for verifying that the prompt is launched and that cancel/fallback behavior works.
4. FragmentScenario with Fake BiometricPrompt
AndroidX provides FragmentScenario to launch a fragment in isolation. Combine it with a fake BiometricPrompt injected via a service locator or constructor.
@ExperimentalCoroutinesApi
class LoginFragmentTest {
private lateinit var fakePrompt: FakeBiometricPrompt
@Before
fun setUp() {
fakePrompt = FakeBiometricPrompt(Result.Success)
// Replace the singleton or provider used by the fragment
BiometricPromptProvider.setInstance(fakePrompt)
}
@Test
fun onBiometricSuccess_navigates() = launchFragmentInContainer<LoginFragment>(themeResId = R.style.AppTheme)
.onFragment { fragment ->
// Simulate user tapping the biometric button
fragment.view?.findViewById<RadioButton>(R.id.btn_biometric)?.performClick()
// Advance time to let the fake prompt callback execute
advanceTimeBy(100)
// Verify that the fragment has navigated (e.g., via Navigation component)
val navController = Navigation.findNavController(fragment.requireView())
assertTrue(navController.currentDestination?.id == R.id.homeFragment)
}
}
FakeBiometricPrompt simply invokes the supplied callback with the predetermined result after a delay. This approach lets you test UI state changes, navigation, and side effects without any OS interaction.
5. Cloud‑Based Device Farm (Firebase Test Lab)
For matrix coverage across OS versions and OEMs, upload your APK (or App Bundle) to Firebase Test Lab and run the instrumentation suite you already have (Espresso/UI Automator).
# Install gcloud if not present
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud init
# Create a test matrix
gcloud firebase test android run \
--type instrumentation \
--app app-debug.apk \
--test app-debug-test.apk \
--device model=Pixel3,version=30,locale=en,orientation=portrait \
--device model=SM-G991U,version=31,locale=en,orientation=portrait \
--timeout 5m
The command runs your tests on a Pixel 3 (stock Android) and a Samsung Galaxy S21 (One UI) in parallel. Collect results via the Firebase console or gsutil to pull test logs, screenshots, and video recordings.
6. Using SUSA for Autonomous Exploration
SUSA (SUSATest) can be pointed at your APK and will autonomously explore the app with a set of built‑in personas (e.g., “impatient”, “elderly”, “adversarial”). Because it does not rely on pre‑written test scripts, it often reaches states that manual testers overlook—such as a biometric login button that appears only after a specific sequence of navigation steps, or a prompt that is shown behind a full‑screen dialog due to a race condition.
To invoke SUSA:
pip install susatest-agent
susatest explore --apk path/to/your/app.apk \
--personas curious impatient elderly adversarial \
--output-dir ./susa-reports \
--max-depth 6 \
--timeout 120
The agent will generate a report that includes:
- Discovered screens and transitions.
- Any crashes, ANRs, or unhandled exceptions observed during exploration.
- Detected accessibility violations (WCAG contrast, missing labels).
- Security hints such as activities exported without protection.
- A set of auto‑generated regression scripts (Appium for Android, Playwright for web) that you can commit to your CI pipeline.
Because SUSA treats the biometric login button like any other UI element, it will attempt to tap it with each persona’s timing profile—some personas tap rapidly, some wait for a long delay, some repeatedly cancel the prompt. This variability surfaces bugs like:
- The app crashing when the biometric prompt is dismissed while a network request is in flight.
- The fallback to PIN not being offered when the “impatient” persona cancels the prompt twice in quick succession.
- TalkBack not announcing the prompt when the “elderly” persona navigates via swipe gestures because focus is left on a background view.
Integrating the SUSA step into your nightly build gives you continuous, script‑free coverage that complements your deterministic Espresso/UI Automator tests.
Common Production Bugs and Gotchas
Even with a solid test matrix, certain issues tend to slip into production. Below are the most frequent patterns we have observed across multiple Android apps, along with concrete mitigation steps.
| Issue | Root Cause | Symptom in the Wild | Fix / Guardrail |
|---|---|---|---|
| Prompt appears behind a dialog | FragmentTransaction commits before the BiometricPrompt is shown; a full‑screen loading dialog is displayed via Window.setFlags(FLAG_NOT_TOUCHABLE). | User sees a blank screen; tapping does nothing; logs show onAuthenticationError with USER_CANCELED. | Ensure any blocking UI is dismissed *before* calling authenticate(). Use a LifecycleObserver to listen for ON_START and only then invoke the prompt. |
| CryptoObject reused after lockout | App caches the Cipher or Signature object in a singleton and reuses it after a lockout event. | After too many failed attempts, subsequent encryption throws KeyPermanentlyInvalidatedException, causing a crash or silent data loss. | Invalidate the cached crypto object on any onAuthenticationError with LOCKOUT or ERROR_INVALIDATED_KEY. Re‑create a fresh object from the Keystore on each authentication attempt. |
| Missing fallback on devices without biometric hardware | Code assumes BiometricManager.canAuthenticate() == BIOMETRIC_SUCCESS and hides the alternative login button. | On low‑end devices without a fingerprint sensor, the login screen shows only a disabled biometric button, leaving users stuck. | Always keep the username/password or PIN entry visible; gate the biometric button behind the canAuthenticate() check, but never hide the fallback entirely. |
| TalkBack reads placeholder text instead of prompt title | The PromptInfo title is set programmatically after the fragment’s onCreateView, but TalkBack reads the view’s initial content description. | Visually impaired users hear “Login” instead of the app‑specific prompt, causing confusion. | Set the PromptInfo title *before* building the BiometricPrompt, and if you need to change it dynamically, recreate the prompt object. |
| Race condition causing multiple prompts | A rapid double‑tap on the login button triggers two authenticate() calls before the first prompt is dismissed. | Two overlapping system dialogs appear; the second one is ignored, but the first callback may be delivered to the wrong caller, leading to state corruption. | Disable the login button immediately after the first call and re‑enable it only after receiving a callback (success, error, or cancel). Use a simple AtomicBoolean flag. |
| BiometricPrompt leaks memory via anonymous inner class | The AuthenticationCallback is defined as an anonymous inner class holding a reference to the Activity or ViewModel. | Over time, repeated logins cause a slow increase in heap usage, eventually leading to OOM on low‑RAM devices. | Use a top‑level class or a object declaration for the callback, or clear references in onDestroy(). |
| Incorrect error code mapping on OEM ROMs | Vendor‑specific help codes (e.g., 1001 for “sensor dirty”) are not handled, causing the app to treat them as generic errors. | Users see a generic “Authentication failed” message even though the sensor just needs cleaning. | Maintain a map of known OEM help codes to user‑friendly messages; log any unknown code for future triage. |
| Biometric authentication bypass via overlay | An app with SYSTEM_ALERT_WINDOW draws a transparent overlay that captures touch events before the system prompt receives them. | Malicious app can record the user’s fingerprint gesture or trigger a false success by injecting events. | Declare your activity with android:excludeFromRecents="true" and android:taskAffinity=""; more importantly, ensure your app’s target SDK is ≥ 28 and that you do not grant SYSTEM_ALERT_WINDOW to any third‑party code. |
| Session token not invalidated after biometric logout | The app retains the same JWT or session ID after the user logs out via biometric login, assuming the token is still valid. | After a user logs out and another user logs in on the same device, the second user gains access to the first user’s data. | On any logout flow (explicit button or system‑triggered biometric cancel), clear all auth tokens and force a network re‑auth. Treat biometric login as a fresh authentication event, not a mere session extension. |
Mitigation Checklist (Derived from the Above)
- Lifecycle guard – Only call
authenticate()when the fragment/activity is at leastSTARTED. - State flag – Use an atomic boolean or MutableStateFlow to prevent concurrent auth calls.
- PromptInfo immutability – Build
PromptInfoonce; if you need to change title/icon, create a newBiometricPrompt. - Fallback visibility – Never hide username/password or PIN entry; keep them accessible even when biometrics are available.
- Crypto object scoping – Obtain a fresh
Cipher/Signaturefrom the Keystore for each authentication attempt. - Error code handling – Map
BiometricPrompt.ErrorCodesand known OEM help codes to user messages; log unknowns. - Accessibility – Verify that TalkBack announces the prompt title and that focus returns to a logical element after success/failure.
- Security – Ensure no raw biometric data appears in logs (
logcat), and that the prompt window is flagged secure (setConfirmationRequired(false)does not disable FLAG_SECURE). - Cleanup – On
onDestroy()or when the fragment is removed, clear any references to theBiometricPromptor its callback to avoid leaks.
Short Checklist for Biometric Login Testing
| Area | Item | Manual? | Automated? | Tool |
|---|---|---|---|---|
| Happy path | Fingerprint/face success leads to expected screen | ✅ | ✅ | Espresso + IdlingResource, UI Automator |
| Fallback | Device credential works after cancel | ✅ | ✅ | Espresso |
| Error – HW unavailable | Proper error UI when sensor disabled | ✅ | ✅ | UI Automator |
| Error – Lockout | Lockout message, no crypto, timer respected | ✅ | ✅ | UI Automator + manual wait |
| Error – User cancel | App returns to login, no stray UI | ✅ | ✅ | Espresso |
| Rapid fire | Only one prompt shown, subsequent taps ignored | ✅ | ✅ | Espresso |
| Rotation | Prompt survives orientation change | ✅ | ✅ | UI Automator |
| Accessibility | TalkBack reads prompt, focus restored | ✅ | ❌ (needs manual verification) | TalkBack + manual |
| Security/privacy | No biometric data in logs, prompt flagged secure | ✅ | ✅ (logcat check) | adb logcat |
| Crypto invalidation | Key unusable after lockout | ✅ | ✅ (unit test) | JUnit + MockKeystore |
| OOM / Leaks | No memory growth after repeated auth cycles | ❌ | ✅ (Android Studio Profiler) | Profiler |
| Persona exploration | Curious, impatient, adversarial, elderly personas reach biometric screen | ❌ | ✅ (SUSA) | susatest-agent |
| Regression | Test passes after OS/Play Services update | ❌ | ✅ (Firebase Test Lab) | gcloud firebase test android |
Run this checklist before each release candidate; any unchecked item should trigger a bug ticket.
Closing Takeaways
Biometric login is a deceptively simple feature that touches hardware, OS frameworks, cryptography, and UI layers all at once. A thorough test strategy must therefore span:
- Functional verification – happy path, error handling, fallback, and timing sensitivities.
- Accessibility validation – ensure that users relying on TalkBack, enlarged fonts, or alternative input methods receive the same experience.
- Security and privacy guarantees – confirm that no biometric material leaks, that keys are properly invalidated, and that the prompt cannot be obscured or intercepted.
- Device and version coverage – test across at least one stock Android device, one major OEM skin, and multiple API levels to catch vendor‑specific quirks.
- Exploratory, persona‑driven discovery – employ an autonomous agent like SUSA to surface edge cases that scripted tests never consider, such as race conditions caused by rapid cancellations or accessibility focus loss.
By combining deterministic unit and instrumented tests with cloud‑based device farms and occasional autonomous runs, you gain confidence that the biometric login flow will remain stable, usable, and secure as the OS evolves, OEMs update their skins, and your own app gains new features.
Apply the checklist, automate the repetitive checks, and let the exploratory tooling surface the surprises—your users will thank you with fewer abandoned logins and higher trust in your app’s security.
---
*End of guide.*
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