DeviceRunners Technical Architecture Overview
This page provides a comprehensive technical overview of all DeviceRunners components, features, and architectures. This serves as a reference for understanding the entire ecosystem before diving into specific documentation.
Overview
DeviceRunners is a comprehensive testing framework for .NET MAUI applications that supports multiple testing approaches across different platforms. The project consists of three main testing strategies:
dotnet testIntegration - Standard .NET test workflow via theDeviceRunners.Testing.TargetsNuGet package (recommended)- Visual Test Runners - Interactive UI-based test execution for development and manual testing
- CLI Test Runners - Automated command-line test execution for advanced scenarios
Supported Platforms
| Platform | dotnet test |
Visual Runner | CLI Runner | XHarness (Legacy) |
|---|---|---|---|---|
| Android | ✅ | ✅ | ✅ | ✅ |
| iOS | ✅ | ✅ | ✅ | ✅ |
| macOS (Mac Catalyst) | ✅ | ✅ | ✅ | ✅ |
| Windows (WinUI 3) | ✅ | ✅ | ✅ | ❌ |
Supported Testing Frameworks
| Framework | Visual Runner | dotnet test / CLI |
XHarness Runner |
|---|---|---|---|
| Xunit | ✅ | ✅ (any) | ✅ |
| NUnit | ✅ | ✅ (any) | ❌ |
Note
Both dotnet test and the CLI tool are framework-agnostic — they launch the test app and collect results via TCP. They work with any testing framework that the app supports.
Core Architecture Components
1. Core Libraries (DeviceRunners.Core)
- Base interfaces and shared functionality
- Device abstraction layer
- Result channel management
- Application termination handling
2. Visual Test Runners
Visual Runner Core (DeviceRunners.VisualRunners)
- ITestRunner interface - Core test execution
- ITestDiscoverer interface - Test discovery
- CompositeTestRunner - Runs multiple test framework runners
- CompositeTestDiscoverer - Discovers tests across frameworks
- IVisualTestRunnerConfiguration - Configuration management
Framework-Specific Visual Runners
- DeviceRunners.VisualRunners.Xunit - Xunit test runner and discoverer
- DeviceRunners.VisualRunners.NUnit - NUnit test runner and discoverer
MAUI Integration (DeviceRunners.VisualRunners.Maui)
- MAUI app integration via
UseVisualTestRunner() - Visual UI components (pages, view models)
- Automatic runner detection and configuration
- Cross-platform UI implementation
3. XHarness Test Runners (Legacy CLI)
XHarness Core (DeviceRunners.XHarness)
- ITestRunner interface for XHarness execution
- XHarnessDetector - Auto-detection of XHarness environment
- Platform-specific entry points
XHarness Framework Integration
- DeviceRunners.XHarness.Xunit - Xunit support for XHarness
- Platform-specific implementations:
- Android:
DefaultAndroidEntryPointintegration - iOS/Mac Catalyst:
iOSApplicationEntryPointintegration - Windows:
DefaultAndroidEntryPointintegration (reuses the Android base class)
- Android:
XHarness MAUI Integration (DeviceRunners.XHarness.Maui)
- MAUI app integration via
UseXHarnessTestRunner() - Android instrumentation support
- Auto-configuration based on environment variables
4. New CLI Tool (DeviceRunners.Cli)
A modern cross-platform CLI tool that replaces platform-specific PowerShell scripts with unified commands.
Supported Commands
Windows Commands:
windows cert install- Install certificates for MSIX packageswindows cert uninstall- Remove certificateswindows install- Install MSIX applicationswindows uninstall- Uninstall applicationswindows launch- Launch applicationswindows test- Run tests (supports both .msix and .exe files)
Android Commands:
android install- Install APK packagesandroid uninstall- Uninstall applicationsandroid launch- Launch applicationsandroid test- Run tests with logcat capture
macOS Commands:
macos install- Install .app bundlesmacos uninstall- Uninstall applicationsmacos launch- Launch applicationsmacos test- Run tests
iOS Commands:
ios install- Install .app bundles to simulatorios uninstall- Uninstall applications from simulatorios launch- Launch applications on simulatorios test- Run tests on simulator
Network Commands:
listen- Start TCP port listener for test results
CLI Tool Features
- JSON and verbose output modes (
--output json) - XML and text output modes (
--output xml,--output text) - TCP result listening for test execution
- Automatic certificate management (Windows)
- Device/emulator targeting (Android)
- Comprehensive error handling and cleanup
- Cross-platform using .NET and Spectre.Console
5. UI Testing Support
UI Testing Core (DeviceRunners.UITesting)
- UIThreadCoordinator - Thread coordination for UI tests
- Cross-platform UI thread abstraction
UI Testing Framework Integration
- DeviceRunners.UITesting.Xunit - Xunit UI testing support
UIFactandUITheoryattributesUITestRunner,UITestCaseRunner- Custom test executionUIFactDiscoverer,UITheoryDiscoverer- Test discovery
UI Testing MAUI Integration (DeviceRunners.UITesting.Maui)
- MAUI-specific UI thread coordination
- Integration via
ConfigureUITesting()extension method
Test Execution Patterns
Visual Runner Pattern
var builder = MauiApp.CreateBuilder();
builder.UseVisualTestRunner(conf => conf
.EnableAutoStart(true)
.AddTestAssembly(typeof(MyTests).Assembly)
.AddXunit()
.AddNUnit()
.AddConsoleResultChannel()
.AddFileResultChannel(new FileResultChannelOptions { Directory = "test-results" })
.AddTcpResultChannel(new TcpResultChannelOptions
{
HostNames = ["localhost", "10.0.2.2"], // 10.0.2.2 is the Android emulator's alias for the host machine
Port = 16384,
Formatter = new EventStreamFormatter(),
Required = false,
Retries = 3,
RetryTimeout = TimeSpan.FromSeconds(5),
Timeout = TimeSpan.FromSeconds(30)
}));
XHarness Runner Pattern
var builder = MauiApp.CreateBuilder();
builder.UseXHarnessTestRunner(conf => conf
.AddTestAssembly(typeof(MyTests).Assembly)
.AddXunit());
UI Testing Pattern
[UIFact]
public void TestUIComponent()
{
// Test runs on UI thread automatically
var entry = new Entry { Text = "test" };
var handler = entry.ToHandler(MauiContext);
Assert.Equal("test", handler.PlatformView.Text);
}
Result Channel System
The framework supports multiple result output channels:
- Console Channel - Console output
- TCP Channel - Network-based result streaming
- File Channel - File-based result output (via
AddFileResultChannel()) - Custom Channels - Extensible channel system
Configuration Management
Visual Test Runner Configuration
- Assembly discovery and loading (via
AddTestAssembly()andAddTestAssemblies()) - Framework-specific discoverer registration
- Result channel configuration
- Auto-start and auto-terminate options (via
EnableAutoStart())
XHarness Test Runner Configuration
- Environment variable detection
- Test assembly registration
- Skip category configuration
- Output directory management
Platform-Specific Implementation Details
Android
- Uses Android instrumentation for XHarness
- ADB integration for CLI tool
- Logcat capture and management
- Emulator and device targeting
iOS/macOS
- Uses XHarness entry points
- App bundle management
- Simulator and device support
- Certificate handling (macOS)
Windows
- MSIX package support
- Certificate management and installation
- Dependency installation
- Both packaged (.msix) and unpackaged (.exe) app support
- PowerShell script automation converted to C#
Testing Framework Integration
Xunit Integration
- Custom test case runners for UI thread execution
- Theory and fact attribute support
- Parallel execution configuration
- Long-running test detection
NUnit Integration
- NUnit test assembly building
- Test listener implementation
- Result aggregation and reporting
- Filter support for test selection
Development and Extension Points
Creating Custom Test Runners
Implement ITestRunner interface:
public class CustomTestRunner : ITestRunner
{
public Task RunTestsAsync(IEnumerable<ITestAssemblyInfo> testAssemblies, CancellationToken cancellationToken = default);
public Task RunTestsAsync(IEnumerable<ITestCaseInfo> testCases, CancellationToken cancellationToken = default);
}
Creating Custom Test Discoverers
Implement ITestDiscoverer interface:
public class CustomTestDiscoverer : ITestDiscoverer
{
public Task<IReadOnlyList<ITestAssemblyInfo>> DiscoverAsync(CancellationToken cancellationToken = default);
}
Adding Custom Result Channels
Extend the result channel system for custom output formats and destinations.
Migration Notes
From PowerShell Scripts to CLI Tool
The new CLI tool (DeviceRunners.Cli) replaces the previous PowerShell-based Windows testing scripts with:
- Cross-platform .NET implementation
- Unified command structure across platforms
- Better error handling and reporting
- JSON output support for automation
- TCP result streaming
From Framework-Specific Runners
The visual runner system provides a unified approach that replaces framework-specific device runners with:
- Multi-framework support in single apps
- Consistent UI across platforms
- Unified configuration and result handling
- Better development-time testing experience
Sample Projects
The repository includes comprehensive sample projects demonstrating:
- Multi-framework test projects (Xunit + NUnit)
- UI testing patterns
- Visual and XHarness runner configurations
dotnet testintegration viaDeviceRunners.Testing.Targets- Platform-specific implementations
- MAUI library testing
DeviceRunners.Testing.Targets Package
The DeviceRunners.Testing.Targets NuGet package enables dotnet test for device platforms by replacing the standard VSTest MSBuild target with a custom implementation that:
- Builds the app for the target platform
- Deploys it using the bundled DeviceRunners CLI tool
- Launches the app with configuration for auto-run and TCP connection
- Collects test results via TCP and writes a TRX file
- Reports results in the standard
dotnet testoutput format
Package Structure
The package ships two MSBuild files and self-contained CLI binaries:
build/
DeviceRunners.Testing.Targets.props # Imported early: disables MTP, sets defaults
DeviceRunners.Testing.Targets.targets # Imported late: custom VSTest target chain
tools/
osx-arm64/DeviceRunners.Cli # Self-contained single-file binary (~20 MB)
osx-x64/DeviceRunners.Cli
win-x64/DeviceRunners.Cli.exe
win-arm64/DeviceRunners.Cli.exe
linux-x64/DeviceRunners.Cli
linux-arm64/DeviceRunners.Cli
MSBuild Target Chain
VSTest (entry point, replaces SDK default)
-> Build (compile the app)
-> _DeviceRunnersRunTests (orchestrator)
-> _DeviceRunnersPrepareArgs (common + platform-specific CLI args)
-> _DeviceRunnersExecTests (single Exec, captures exit code)
-> _DeviceRunnersReportResults (parse TRX, emit summary)
Platform detection uses $(_DeviceRunnersPlatform) computed once from GetTargetPlatformIdentifier. Each platform has its own args target that assembles the CLI command. The _DeviceRunnersExecTests target runs a single Exec with IgnoreExitCode="true" and captures the exit code for clean error reporting.
Exit Code Protocol
| Code | Meaning | MSBuild Output |
|---|---|---|
| 0 | All tests passed | No error |
| 1 | Test failures | error TESTERROR: Test summary: ... |
| 2 | App crashed | error TESTERROR: Test summary: ... (incomplete: app crashed) |
For more details, see Using dotnet test.
Future Architecture Considerations
The architecture is designed for extensibility:
- New testing frameworks can be added via ITestRunner/ITestDiscoverer
- New platforms can be supported via platform-specific implementations
- New result channels can be added for different output needs
- CLI tool can be extended with additional platform commands
This technical overview provides the foundation for understanding how all DeviceRunners components work together to provide comprehensive testing capabilities across platforms and testing scenarios.