Repository navigation
test: add Android and iOS device tests run through dotnet test --device - #4506
Merged
Merged
Conversation
3 of 4 tasks
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4506 +/- ##
=======================================
Coverage 93.62% 93.62%
=======================================
Files 175 175
Lines 6227 6227
Branches 743 743
=======================================
Hits 5830 5830
Misses 396 396
Partials 1 1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- Replace the stale ReactiveUI.NonParallel.Mobile.Tests (xUnit runners, missing project reference) with ReactiveUI.Device.Tests - Run TUnit in-process on the device: an Android instrumentation relays results to `dotnet test --device`, an iOS app delegate writes a TRX report and exit code - Cover HandlerSequencer, WithAndroidX registrations, PlatformOperations, activation, ControlFetcherMixins, LayoutViewHost, ReactiveViewHost, AutoSuspendHelper, BundleSuspensionDriver, SharedPreferences, service binding and the AndroidX adapters on a real emulator - Cover NSRunloopSequencer, UIKit registrations, ViewModelViewHost, RoutedViewHost, ReactiveViewController, AppSupportJsonSuspensionDriver and IndexNormalizer on the iOS simulator - Work around TUnit subscribing to Console.CancelKeyPress, which throws on Android and iOS - Add the project to the solution and exclude it from the host test runs in ci-build.yml and sonarcloud.yml - Add device-tests.yml, which calls the actions-common device-tests workflow
- Create the window from a scene delegate, since iOS 26 obsoletes the screen-bounds UIWindow constructor - Start UIKit from a top-level entry point, which TUnit's Main-method analyzer accepts - Turn off trimming and trim analysis for the untrimmed iOS app, and drop the Mono-only interpreter setting - Target net11.0-android37, the Android framework the libraries ship, so no extra library build is needed
glennawatson
force-pushed
the
test/device-tests
branch
from
September 26, 2026 10:44
3a43575 to
46fb4d7
Compare
…window tests ViewModelViewHost owns the controllers it resolves and disposes the one it replaces. ReplacingViewModel_SwapsTheChildController read ParentViewController on that disposed controller, which sent a message to a released native object and crashed the app with SIGSEGV. The test now checks the old controller through managed state and the host's own hierarchy. The tests that show controllers share the app's one window, so they run under a NotInParallel key; parallel runs replaced each other's root controller midway. The iOS head keeps the trim analyzer on. TestViewController passes its view model changes to WhenActivated, so it uses the trim-safe overload.
ChrisPulman
approved these changes
Sep 26, 2026
glennawatson
enabled auto-merge (squash)
September 26, 2026 12:09
|
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.



Summary
ReactiveUI's Android and iOS platform code now has tests that run on a real emulator and simulator, in CI and locally.
ReactiveUI.Device.TestsreplacesReactiveUI.NonParallel.Mobile.Tests. The old project used xUnit and NUnit runners, referenced a project that no longer exists, and was never built.dotnet test --device. An instrumentation runs TUnit in the app and streams each result back, anddotnet testwrites the TRX report on the host.HandlerSequencer, theWithAndroidXregistrations,PlatformOperations, activity and fragment activation,StartActivityForResultAsync,ControlFetcherMixinson views, activities, layout hosts and AndroidX fragments,LayoutViewHost,ReactiveViewHost,AutoSuspendHelper,BundleSuspensionDriver, shared-preference changes, service binding, and the RecyclerView and pager adapters.NSRunloopSequencer, the UIKit registrations,ViewModelViewHost,RoutedViewHost,ReactiveViewControlleractivation,AppSupportJsonSuspensionDriverandIndexNormalizer.reactiveui.slnx, so every CI leg builds it.ci-build.ymlandsonarcloud.ymlleave it out of the host test run with!tests/ReactiveUI.Device.Tests/**.device-tests.ymlruns both heads through the new actions-common device-tests workflow. It usesworkflow-common-device-tests.yml@main.Why
Nothing exercised the code under
Platforms/android,apple-commonanduikit-commonorReactiveUI.AndroidX, because it only runs on a device.Breaking changes
None. Only tests and CI change.
How this was verified
The Android head ran on a local emulator, in Debug and Release, through the same device-tests script CI runs.
device-tests (ios)job.dotnet run --file ../actions-common/scripts/device-tests.cs -- android --project src/tests/ReactiveUI.Device.Tests/ReactiveUI.Device.Tests.csproj; the project README has the details.Notes for the reviewer
Start with
Runner/DeviceTestSession.csand the two heads,Platforms/Android/TestInstrumentation.csandPlatforms/iOS/IosTestHost.cs; the test classes are straightforward.Runner/ConsoleCancelKeyShim.csworks around a TUnit 1.69 bug. TUnit subscribes toConsole.CancelKeyPressat the start of a run and skips that only in the browser, so every run on Android or iOS fails before the first test. The shim fills the console's signal registration with an inert one. It should go once TUnit guards Android and iOS; that needs an issue on TUnit.EnableTrimAnalyzerto false. The app is not trimmed (MtouchLink=None), so the analysis only reports the reflection paths the tests cover; the SDK's MSTest runner does the same. Please confirm that is acceptable under the no-suppression rule.LayoutViewHostwithResolveStrategy.ExplicitOptOutalways throws. The host's own publicViewproperty is a writableView, so the opt-out strategy tries to wire it by name and fails. The tests cover opt-out on a plain view instead; the host bug is left for a separate fix.ReactiveActivity<TViewModel>'sIViewFor.ViewModelsetter assigns the field without raising a change, unlike the other hosts.ContextExtensions.ServiceBounddisposes the context it was given when the subscription ends, so the tests pass it aContextWrapper.*Unsafeview hosts, which are not onmainyet (fix!: make every default view host AOT safe on Binding 8.1.0 #4505), andUsbManagerExtensions, which needs USB hardware. The device run collects no coverage: the coverage collector instruments a desktop test process.Checklist