IVSoftware.WinOS.MSTest.Extensions.STA 1.0.0-beta

Prefix Reserved
This is a prerelease version of IVSoftware.WinOS.MSTest.Extensions.STA.
The owner has unlisted this package. This could mean that the package is deprecated, has security vulnerabilities or shouldn't be used anymore.
dotnet add package IVSoftware.WinOS.MSTest.Extensions.STA --version 1.0.0-beta
                    
NuGet\Install-Package IVSoftware.WinOS.MSTest.Extensions.STA -Version 1.0.0-beta
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="IVSoftware.WinOS.MSTest.Extensions.STA" Version="1.0.0-beta" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="IVSoftware.WinOS.MSTest.Extensions.STA" Version="1.0.0-beta" />
                    
Directory.Packages.props
<PackageReference Include="IVSoftware.WinOS.MSTest.Extensions.STA" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add IVSoftware.WinOS.MSTest.Extensions.STA --version 1.0.0-beta
                    
#r "nuget: IVSoftware.WinOS.MSTest.Extensions.STA, 1.0.0-beta"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package IVSoftware.WinOS.MSTest.Extensions.STA@1.0.0-beta
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=IVSoftware.WinOS.MSTest.Extensions.STA&version=1.0.0-beta&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=IVSoftware.WinOS.MSTest.Extensions.STA&version=1.0.0-beta&prerelease
                    
Install as a Cake Tool

IVSoftware.WinOS.MSTest.Extensions.STA

STARunner provides a deterministic Single Threaded Apartment (STA) environment for MSTest. It hosts a lightweight WinForms message pump on a dedicated UI thread, giving tests access to real Windows UI semantics when required by WinForms, COM, or synchronization-context - dependent code.


Test-Driven UI Component Development

Having a test container sandbox for UI components under development accelerates the cycle - as long as the UI thread and message loop are predictable and stable. STARunner provides that environment with minimal syntax overhead.

[TestMethod]
public async Task Test_CanonicalPOC()
{
    using var sta = new STARunner(isVisible: false);
    await sta.RunAsync(localStaTest);

    // Encapsulate the local testing to be done on the STA thread.
    async Task localStaTest()
    {
        Assert.IsFalse(
            sta.MainForm.InvokeRequired,
            $"Expecting confirmation of UI thread context. No marshal is needed.");

        // Manipulate the UI
        sta.MainForm.Text = "Hello";
        Assert.IsInstanceOfType<SilentRunner>(sta.MainForm);
        Assert.IsTrue(sta.MainForm.IsHandleCreated);
        Assert.AreEqual("Hello", sta.MainForm.Text);

        await Task.CompletedTask;
    }
}

To test your app's Main Form, pass its Type into the constructor of STARunner.

[TestMethod]
public async Task Test_CustomUserForm()
{
    using var sta = new STARunner(isVisible: false, typeof(UserForm));
    await sta.RunAsync(localStaTest);

    #region L o c a l F x 
    async Task localStaTest()
    {
        Assert.IsFalse(
            sta.MainForm.InvokeRequired,
            $"Expecting confirmation of UI thread context. No marshal is needed.");

        // Manipulate the UI
        sta.MainForm.Text = "Hello";
        Assert.IsInstanceOfType<UserForm>(sta.MainForm);
        Assert.IsTrue(sta.MainForm.IsHandleCreated);
        Assert.AreEqual("Hello", sta.MainForm.Text);

        await Task.Delay(TimeSpan.FromSeconds(2.5));
    }
    #endregion L o c a l F x
}

class UserForm : Form 
{
    public UserForm()
    {
        Text = nameof(UserForm);
        BackColor = Color.AliceBlue;
        StartPosition = FormStartPosition.CenterScreen;
    }
}

Either way, everything inside RunAsync runs on the STA thread with normal WinForms behavior (layout, events, handle creation, etc.).


Project Setup

Your test project must target Windows and enable WinForms:

<PropertyGroup>
  <TargetFramework>net8.0-windows</TargetFramework>
  <UseWindowsForms>True</UseWindowsForms>
</PropertyGroup>

Core Concepts

Real Message Pump

STARunner creates an internal form and calls Application.Run, supplying:

  • a UI thread with a message queue
  • proper synchronization context
  • predictable control initialization
Silent or Visible Mode

By default the form is hidden but alive. You can surface it at any time:

sta.MainForm.IsSilent = false;
RunAsync

RunAsync marshals work onto the STA thread:

await sta.RunAsync(async () =>
{
    var btn = new Button();
    btn.PerformClick();
    await Task.CompletedTask;
});
Deterministic Teardown

Disposing STARunner closes the form, exits the loop, and joins the thread.
No leaked UI threads, no phantom message pumps.


Example: Direct UI Execution

[TestMethod]
public async Task Test_MonolithicVisible()
{
    using var sta = new STARunner(isVisible: true);

    await sta.RunAsync(async () =>
    {
        sta.MainForm.Text = "Main Form";

        for (int n = 5; n >= 0; n--)
        {
            sta.MainForm.Text = $"Shutdown in {n}";
            await Task.Delay(1000);
        }
    });
}

Inside RunAsync, the test is effectively a tiny WinForms app.


Example: Popup UI in a Silent Environment

await sta.RunAsync(async () =>
{
    var popup = new Form
    {
        Size = new Size(300, 100),
        FormBorderStyle = FormBorderStyle.None
    };

    var label = new Label
    {
        Dock = DockStyle.Fill,
        TextAlign = ContentAlignment.MiddleCenter
    };

    popup.Controls.Add(label);
    popup.Show();
    popup.PerformLayout();
    popup.Update();

    for (int n = 5; n >= 0; n--)
    {
        label.Text = $"Shutdown in {n}";
        await Task.Delay(1000);
    }
});

Summary

STARunner supplies:

  • a dedicated STA UI thread
  • an isolated WinForms message pump
  • true handle, layout, and event semantics
  • transparent async boundaries via RunAsync
  • deterministic teardown

Ideal for MSTest scenarios requiring WinForms behavior, COM STA affinity, or UI-thread - dependent components, without requiring visible UI unless requested.

Product Compatible and additional computed target framework versions.
.NET net8.0-windows7.0 is compatible.  net9.0-windows was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated

Initial alpha release. Core STA execution model is stable in internal testing, but requires additional flight time in real-world MSTest scenarios before APIs are finalized.