test(ble): add Robolectric coverage for the bonding-interruption fix (#5849)#5850
Merged
Conversation
…ectric harness Adds the first Android-target (androidHostTest / Robolectric) test coverage for the BLE bonding-interruption fix, plus reusable scaffolding so future BLE tests have minimal boilerplate. No production code changed. - core/testing: make the shared FakeBluetoothRepository failure-injectable (BondOutcome Success/Fail/Security + bondCalls recording, additive/backward compatible); add a reusable Robolectric bond-state DSL (RobolectricBleBonding); androidMain failBondWithSecurityException helper (SecurityException is JVM-only). - core/ble: AndroidBluetoothRepositoryBondTest exercises the real bond() — createBond()==false → BONDING then broadcast resume / BOND_NONE → "Failed to initiate bonding" / mid-method race to BONDED (custom shadow); plus already-bonded early return, BOND_NONE-from-BONDING failure, isBonded/isValid. - feature/connections: AndroidScannerViewModelBondingTest covers requestBonding via the public onSelected — armed on success and on generic Exception, not armed + error surfaced on SecurityException; extract ScannerViewModelHarness and refactor the existing ScannerViewModelTest onto it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pers, add cases Refinements from craft-review (no production change): - AndroidScannerViewModelBondingTest: run on the harness TestDispatcher so the scheduler that advanceUntilIdle() drives is the one the ViewModel actually uses. - AndroidBluetoothRepositoryBondTest: add explicit assertions to the two previously assertion-free tests (already-bonded now also asserts isBonded); add coverage for the createBond()==true happy path and for a spurious BOND_NONE (prev != BONDING) being ignored. Now 9 tests. - RobolectricBleBonding: remove unused denyBluetoothConnectPermission and resetBleBondingShadows; document distinct-MAC isolation. - FakeBluetoothRepository: note the BondOutcome Fail/Security split is call-site intent only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The BLE bonding-interruption fix in #5849 shipped with no automated coverage —
the affected classes are in
androidMainand touch the Android Bluetooth framework,and neither module had any Android-target (Robolectric) test harness. This PR closes
that gap and adds reusable scaffolding so BLE test coverage can grow on top of it.
No production code is changed —
bond()andrequestBonding()are exercised exactlyas shipped.
Note
Built on top of #5849 (currently in the merge queue). Once #5849 lands on
mainthis rebases cleanly; until then the two production methods under test come from
that PR.
🌟 New Tests
AndroidBluetoothRepositoryBondTest(core/ble, Robolectric) — covers the realbond():createBond()==falsere-check resolving to BONDED (mid-method race, via ascoped custom shadow), staying in BONDING then resuming on a later
ACTION_BOND_STATE_CHANGED(BOND_BONDED)broadcast, and failing with"Failed to initiate bonding" otherwise; plus the already-bonded early return,
createBond()==truehappy path, rejection (BOND_NONEfromBONDING), a spuriousBOND_NONEbeing ignored, andisBonded/isValid.AndroidScannerViewModelBondingTest(feature/connections, Robolectric) — coversrequestBondingvia the publiconSelected: the transport is armed on bond successand on a generic exception (the interrupted-bonding case the fix targets), and is
not armed — with an error surfaced — on a permissions
SecurityException.🛠️ Reusable test scaffolding
RobolectricBleBonding(core/testing/androidMain) — a small DSL overShadowBluetoothDevicefor driving bond state and firing bond-state broadcasts.FakeBluetoothRepositorymade failure-injectable (additive, backward-compatible:bondOutcomedefaults to the existing success behavior; recordsbondCalls).ScannerViewModelHarness(feature/connections/commonTest) bundles the ViewModel'scollaborators; the existing
ScannerViewModelTestwas refactored onto it (noduplicated construction).
🧹 Chores
androidHostTestdependencies (core:testing, coroutines-test, androidx-test-ext)to
core/bleandfeature/connections. No new modules/source-sets, so no CIpath-filter change.
Testing Performed
AndroidBluetoothRepositoryBondTest(9),AndroidScannerViewModelBondingTest(4).ScannerViewModelTestonto the shared harness (assertions unchanged)../gradlew spotlessCheck detekt assembleDebug :core:testing:allTests :core:ble:allTests :feature:connections:allTests— all green.Chose Robolectric (
androidHostTest) over instrumented tests: it simulateseverything needed (bond state,
createBond(), bond-state broadcasts) on the JVM, runswithout a device in CI, and required no production seam — consistent with current
Android guidance to prefer Robolectric for framework-dependent unit logic.