Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 4, 2025

  • Audit ReactiveUI.Tests for static/global state usage (RxApp, Locator, MessageBus, ViewLocator, ModeDetector)
  • Create helper scope classes to snapshot and restore static state
    • RxAppSchedulersScope for RxApp schedulers
    • LocatorScope for Splat dependency resolver
    • MessageBusScope for MessageBus.Current
  • Mark affected test fixtures as [NonParallelizable]
    • MessageBusTest.cs (uses Locator.CurrentMutable, MessageBus.Current)
    • RandomTests.cs (uses RxApp, ViewLocator.Current, Locator, MessageBus.Current)
    • RxAppTest.cs (uses RxApp.MainThreadScheduler)
    • ReactiveCommandTest.cs (uses RxApp.EnsureInitialized)
    • PocoObservableForPropertyTests.cs (uses RxApp.EnsureInitialized)
    • Platform-specific tests (RoutedViewHostTests, ViewModelViewHostTests, etc.)
    • AwaiterTest.cs (uses RxApp.TaskpoolScheduler)
  • Apply helper scopes in test setup/teardown where needed
  • Document rationale for non-parallelizable fixtures
  • Verify tests run deterministically (on Windows environment)

Note: Build environment requires Windows with .NET 8/9/10 SDKs. Current Linux environment cannot build/test but can prepare code changes.

Original prompt

This section details on the original issue you should resolve

<issue_title>Stabilize ReactiveUI.Tests by isolating static state and de-parallelizing affected tests</issue_title>
<issue_description>Goal: Make tests deterministic. Audit tests for usage of static/global state and ensure each such test:

  1. does not run in parallel, and
  2. restores all mutated static state to its prior values (via helper scopes/fixtures as needed).

This work is blocked unless the build & test environment is set up exactly as specified below. Follow the pre-flight steps first.


🔒 Pre-flight: Build Environment Requirements (must be completed before any code changes)

Cloning the Repository

CRITICAL: Perform a full, recursive clone. A shallow clone (--depth 1) will fail because the build reads git version info.

# Full recursive clone
git clone --recursive https://github.com/reactiveui/reactiveui.git
cd reactiveui

Required Tools

  • .NET SDKs: 8.0, 9.0, and 10.0

CRITICAL: Install all three SDKs via the official script:

# Download the installation script
Invoke-WebRequest -Uri https://dot.net/v1/dotnet-install.ps1 -OutFile dotnet-install.ps1

# Install .NET 8 SDK
./dotnet-install.ps1 -Channel 8.0 -InstallDir ./.dotnet

# Install .NET 9 SDK
./dotnet-install.ps1 -Channel 9.0 -InstallDir ./.dotnet

# Install .NET 10 SDK
./dotnet-install.ps1 -Channel 10.0 -InstallDir ./.dotnet

(Tip: ensure ./.dotnet is on PATH for this shell session, or call it explicitly via ./.dotnet/dotnet.)

Solution Files

  • Main solution: src/ReactiveUI.sln
  • Integration test solutions live under integrationtests/ (not required for this task)

🛠️ Build & Test Commands (Windows PowerShell or CMD, repository root)

CRITICAL: dotnet workload restore must be run from /src before building.

dotnet --info

# CRITICAL: restore workloads from /src
cd src
dotnet workload restore
cd ..

# Restore packages
dotnet restore src/ReactiveUI.sln

# Build (requires Windows for platform targets)
dotnet build src/ReactiveUI.sln -c Release -warnaserror

# Run tests (includes AOT tests requiring .NET 9.0)
dotnet test src/ReactiveUI.sln -c Release --no-build

Note: Building on Linux/macOS will fail due to net*-windows targets and AOT tests. Use Windows.


🧭 Context & Example Failure

We’re seeing intermittent failures tied to static/global state. Example:

Failed AutoPersistDoesntWorkOnNonDataContractClasses
ReactiveUI.UnhandledErrorException ... Could not find a ICreatesObservableForProperty ...
... your service locator is probably broken ...
at ReactiveUI.RxApp.<>c__DisplayClass9_0.<.cctor>b__2() ...

This indicates tests mutate or rely on global/static state (e.g., RxApp, service locator, schedulers, message bus, etc.) without restoring it. Running in parallel amplifies the flakiness.


✅ What to do

1) Discover tests that touch static/global state

Search for usages of well-known static entry points or singletons anywhere under src/ReactiveUI.Tests:

  • ReactiveUI: RxApp., MessageBus., SuspensionHost., Interaction., ModeDetector., LogHost.
  • Splat / DI: Locator., Locator.Current, Locator.CurrentMutable, DependencyResolver, Splat.Locator
  • Any other static members that mutate shared state (caches, registries, global flags, default schedulers, etc.)

Suggested queries (run at repo root):

git grep -n "RxApp\." -- src/ReactiveUI.Tests
git grep -n "Locator\." -- src/ReactiveUI.Tests
git grep -n "MessageBus\." -- src/ReactiveUI.Tests
git grep -n "SuspensionHost\." -- src/ReactiveUI.Tests
git grep -n "ModeDetector\." -- src/ReactiveUI.Tests
git grep -n "LogHost\." -- src/ReactiveUI.Tests
git grep -n "static " -- src/ReactiveUI.Tests

Output: Build a checklist of test files and specific tests that read or write static/global state.


2) Make affected tests non-parallelizable (targeted)

For each test fixture or test that touches static/global state, explicitly disable parallelization with NUnit:

  • At the fixture level (preferred when multiple tests in a class touch static state):

    using NUnit.Framework;
    
    [TestFixture]
    [NonParallelizable] // or [Parallelizable(ParallelScope.None)]
    public class FooTests { ... }
  • Or at the individual test level if only one or two tests are affected:

    [Test, NonParallelizable]
    public void MyTest() { ... }

Do not disable parallelization assembly-wide. Keep the scope as tight as possible.


3) Introduce helper scopes to snapshot & restore static state

Create small, focused disposable scopes for each area of static state. These should snapshot on construction, and restore on Dispose(). Use them in SetUp/TearDown or in using blocks inside tests.

⚠️ Use the actual APIs present in this codebase—names below are examples. Inspect the concrete properties/me...

Fixes #4165

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@Copilot Copilot AI requested a review from glennawatson October 4, 2025 01:17
Copilot finished work on behalf of glennawatson October 4, 2025 01:17
@glennawatson glennawatson deleted the copilot/fix-b990efcb-487d-41fb-a778-37da69d8b4ca branch October 4, 2025 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stabilize ReactiveUI.Tests by isolating static state and de-parallelizing affected tests

2 participants