Skip to content

Testing and Development Tools

Marc Jones edited this page Dec 24, 2025 · 1 revision

Testing and Development Tools for Avalonia and .NET

Educational guide on available tools for testing, profiling, and accessibility


Avalonia UI Testing

Headless Testing Platform

Avalonia provides headless testing that allows running UI tests without a visible GUI, perfect for CI/CD pipelines.

Official Documentation: Headless Testing | Avalonia Docs

Key Features:

  • Runs on servers without X11/display
  • Tests execute in same process as application
  • Supports XUnit and NUnit
  • Direct access to UI elements and state

Setup:

<PackageReference Include="Avalonia.Headless.XUnit" Version="11.2.5" />

Usage:

[AvaloniaFact]  // Instead of [Fact]
public async Task TestUIBehavior()
{
    var vm = new MainWindowViewModel();
    await Dispatcher.UIThread.InvokeAsync(async () =>
    {
        await vm.LoadDocumentAsync(testPath);
    });

    vm.DocumentName.Should().NotBeEmpty();
}

Source: Headless Platform | Avalonia Docs

Pointer Event Simulation

Avalonia.Headless provides methods to simulate user input:

// Create window
var window = new MainWindow { DataContext = vm };

// Simulate mouse drag
window.SimulatePointerDown(new Point(100, 100), MouseButton.Left);
window.SimulatePointerMove(new Point(200, 150));
window.SimulatePointerUp(new Point(200, 150));

// Simulate keyboard
window.SimulateKeyPress(Key.Delete, RawInputModifiers.None);

Alternative: Appium

For end-to-end testing with actual UI rendering, Appium can be used for cross-platform UI automation.

Community Discussion: Alternative way of UI testing for Avalonia


Accessibility in Avalonia

AutomationProperties

Avalonia 11.1+ includes comprehensive accessibility support for screen readers.

Official Announcement: Avalonia 11.1: Screen Reader Support

Platform Support:

  • ✅ Windows: UI Automation API
  • ✅ macOS: NSAccessibility
  • ✅ Android: TalkBack (PR #17704)
  • ⚠️ Linux: Being implemented (Issue #14275)

Adding Accessibility

XAML Properties:

<Button Command="{Binding OpenFileCommand}"
        AutomationProperties.Name="Open PDF File"
        AutomationProperties.HelpText="Opens a file dialog to select a PDF document">
    Open
</Button>

<ToggleButton IsChecked="{Binding IsRedactionMode}"
              AutomationProperties.Name="Redaction Mode"
              AutomationProperties.HelpText="Enable to draw redaction boxes">
    <PathIcon Data="{StaticResource RedactionIcon}" />
</ToggleButton>

Benefits:

  • Screen reader compatibility (NVDA, JAWS, VoiceOver)
  • WCAG 2.1 compliance
  • Better keyboard navigation
  • UI automation testability

Testing Accessibility

Windows: Use Accessibility Insights macOS: Use Accessibility Inspector (Xcode) Linux: Limited tooling currently available


.NET Diagnostics Tools

dotnet-trace

Collects runtime traces for performance analysis across all platforms.

Official Documentation: dotnet-trace | Microsoft Learn

What it does:

  • Profiles application performance
  • Tracks method calls and timing
  • Monitors memory allocations
  • Analyzes GC behavior

Usage:

# Collect trace from running application
dotnet trace collect --process-id $PID

# Collect trace while running tests
dotnet trace collect -- dotnet test

# Collect specific providers
dotnet trace collect --process-id $PID \
  --providers Microsoft-DotNETCore-SampleProfiler

Analysis:

  • Windows: Open in Visual Studio or PerfView
  • Linux/macOS: Convert to speedscope format
  • Cross-platform: Use dotnet-trace analyze

dotnet-counters

Real-time performance counter monitoring.

Official Documentation: dotnet-counters | Microsoft Learn

What it monitors:

  • CPU usage
  • Memory consumption
  • GC collections
  • Thread pool usage
  • Custom EventCounters

Usage:

# Monitor running application
dotnet counters monitor --process-id $PID

# Monitor specific counters
dotnet counters monitor \
  --process-id $PID \
  --counters System.Runtime,System.Net.Http

EventPipe

Cross-platform tracing infrastructure that powers diagnostic tools.

Official Documentation: EventPipe Overview | Microsoft Learn

Key Insight:

"EventPipe is a runtime component that can be used to collect tracing data, similar to ETW or perf_events. The goal of EventPipe is to allow .NET developers to easily trace their .NET applications without having to rely on platform-specific high-privilege components."

Benefits:

  • Works on Windows, Linux, macOS
  • No administrator privileges required
  • Same API across platforms
  • Integrates with dotnet-trace and dotnet-counters

Custom EventSource:

public sealed class RedactionEventSource : EventSource
{
    public static RedactionEventSource Log = new();

    [Event(1, Level = EventLevel.Informational)]
    public void RedactionStarted(string fileName)
        => WriteEvent(1, fileName);

    [Event(2, Level = EventLevel.Informational)]
    public void RedactionCompleted(string fileName, long durationMs)
        => WriteEvent(2, fileName, durationMs);
}

// Usage in code
RedactionEventSource.Log.RedactionStarted(fileName);
// ... perform redaction ...
RedactionEventSource.Log.RedactionCompleted(fileName, sw.ElapsedMilliseconds);

Performance Benchmarking

BenchmarkDotNet

Industry-standard benchmarking library for .NET.

Official Repository: BenchmarkDotNet on GitHub

Used by: .NET Runtime, .NET Compiler, ASP.NET Core, and 27,400+ projects

Features:

  • Micro-benchmarking with statistical analysis
  • Memory allocation tracking
  • Multi-framework support
  • Profiler integration

Setup:

<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />

Example Benchmark:

public class RedactionBenchmarks
{
    private ContentStreamParser _parser;
    private byte[] _contentStream;

    [GlobalSetup]
    public void Setup()
    {
        _parser = new ContentStreamParser(...);
        _contentStream = LoadTestContentStream();
    }

    [Benchmark]
    public List<PdfOperation> ParseContentStream()
    {
        return _parser.ParseOperations(_contentStream, 792);
    }

    [Benchmark]
    [Arguments(100)]  // Small area
    [Arguments(5000)] // Large area
    public void RedactArea(int areaSize)
    {
        var area = new Rect(100, 100, areaSize, areaSize);
        _redactionService.RedactArea(_page, area, _pdfPath, 150);
    }
}

Running:

cd BenchmarkProject
dotnet run -c Release

Profiler Integration

BenchmarkDotNet integrates with profiling tools:

EtwProfiler (Windows): BenchmarkDotNet Docs

[EtwProfiler]  // Attribute on benchmark class
public class MyBenchmarks { }

PerfCollectProfiler (Linux): Profiling on Linux

[PerfCollectProfiler]
public class MyBenchmarks { }

dotTrace (JetBrains): dotTrace Integration

[DotTraceDiagnoser]
public class MyBenchmarks { }

Testing Best Practices

Test Organization

Unit Tests: Test individual components in isolation

public class CoordinateConverterTests
{
    [Fact]
    public void ImageSelectionToPdfPoints_ConvertsCorrectly()
    {
        var result = CoordinateConverter.ImageSelectionToPdfPointsTopLeft(
            new Rect(100, 100, 200, 50), 150);

        result.X.Should().BeApproximately(48, 0.1);
    }
}

Integration Tests: Test component interactions

public class RedactionIntegrationTests
{
    [Fact]
    public void RedactArea_RemovesTextFromPdf()
    {
        // Arrange: Create PDF
        var pdfPath = TestPdfGenerator.CreateSimpleTextPdf("SECRET");

        // Act: Redact
        _redactionService.RedactArea(page, area, pdfPath, 150);
        document.Save(outputPath);

        // Assert: Text removed
        var text = PdfTestHelpers.ExtractAllText(outputPath);
        text.Should().NotContain("SECRET");
    }
}

UI Tests: Test ViewModel and UI behavior

[AvaloniaFact]
public async Task LoadDocument_UpdatesViewModel()
{
    var vm = new MainWindowViewModel(...);
    await vm.LoadDocumentAsync(testPath);

    vm.DocumentName.Should().NotBeEmpty();
    vm.PageCount.Should().BeGreaterThan(0);
}

CI/CD Integration

GitHub Actions:

- name: Run tests with coverage
  run: dotnet test --collect:"XPlat Code Coverage"

- name: Profile performance
  run: dotnet trace collect -- dotnet test

- name: Run benchmarks
  run: cd Benchmarks && dotnet run -c Release

Tool Comparison

Tool Purpose Platform Effort Use Case
Avalonia.Headless UI Testing All Low Automated UI tests
Appium E2E Testing All High Full integration tests
AutomationProperties Accessibility Win/Mac/Android Low Screen reader support
dotnet-trace Profiling All Low Performance analysis
dotnet-counters Monitoring All Low Real-time metrics
BenchmarkDotNet Benchmarking All Low Micro-benchmarks
EventPipe Tracing All Medium Custom telemetry

References

Official Documentation

Key Articles

Community Resources


Summary

Modern .NET and Avalonia provide comprehensive tooling:

Testing: ✅ Headless UI testing, pointer simulation, accessibility testing Profiling: ✅ dotnet-trace, dotnet-counters, EventPipe (all cross-platform) Benchmarking: ✅ BenchmarkDotNet with profiler integration Accessibility: ✅ AutomationProperties for screen readers

All tools work cross-platform and integrate with CI/CD pipelines. The .NET ecosystem has matured to provide py-spy-like capabilities (dotnet-trace) and comprehensive testing frameworks.

Clone this wiki locally