9

We are in the process of porting a WPF app to .NET Core 3, preview 5. Some NUnit tests need to run in STA threads. How can this be done?

None of the attributes like [STAThread], [RequiresSTA], ... work. This also doesn't work: [assembly: RequiresThread(ApartmentState.STA)]

The Apparent namespace does not seem to be exposed in .NET Core 3.

Has anyone done this?

Sven
  • 175
  • 1
  • 8
  • *The Apparent namespace does not seem to be exposed in .NET Core 3.*. -- Sure it is. https://learn.microsoft.com/en-us/dotnet/api/system.stathreadattribute?view=netcore-3.0 – Daniel Mann Jun 12 '19 at 18:55
  • @DanielMann Yes, you are correct of course. I should have said "The Apartment attribute does not seem to be exposed in NUnit 3.11 for the netstandard2.0 configuration". I got confused, my bad. – Sven Jun 12 '19 at 22:24

3 Answers3

9

ApartmentAttribute was first enabled for .NET Standard 2.0 in NUnit 3.12.

First update your version of the NUnit framework, then use [Apartment(ApartmentState.STA)].

Chris
  • 5,882
  • 2
  • 32
  • 57
1

In order to use STA in WPF unit testing in .Net Core 3 you need to add extension method attribute. Add this class

public class STATestMethodAttribute : TestMethodAttribute
{
    public override TestResult[] Execute(ITestMethod testMethod)
    {
        if (Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
            return Invoke(testMethod);

        TestResult[] result = null;
        var thread = new Thread(() => result = Invoke(testMethod));
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        thread.Join();
        return result;
    }

    private TestResult[] Invoke(ITestMethod testMethod)
    {
        return new[] { testMethod.Invoke(null) };
    }
}

And then use it as

[STATestMethod]
public void TestA()
{
    // Arrange  
    var userControlA = new UserControl();

    //Act


    // Assert

}
Stevan
  • 91
  • 5
0

I recently ported my application to .Net 6 and could not get this to work.

However - implementing IWrapTestMethod seems to work:

using NUnit.Framework;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using NUnit.Framework.Internal.Commands;

namespace NunitExtensions;

/// <summary>
/// This attribute forces the test to execute in an STA Thread.
/// Needed for UI testing.
/// The NUnit <see cref="NUnit.Framework.ApartmentAttribute"/> does not seem to work on .Net 6....
/// </summary>
[AttributeUsage(AttributeTargets.Method, Inherited = false)]
public class UITestAttribute : NUnitAttribute, IWrapTestMethod
{
    public TestCommand Wrap(TestCommand command)
    {
        return Thread.CurrentThread.GetApartmentState() == ApartmentState.STA 
            ? command 
            : new StaTestCommand(command);
    }

    private class StaTestCommand : TestCommand
    {
        private readonly TestCommand _command;

        public StaTestCommand(TestCommand command) : base(command.Test)
        {
            _command = command;
        }

        public override TestResult Execute(TestExecutionContext context)
        {
            TestResult? result = null;
            var thread = new Thread(() => result = _command.Execute(context));
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            thread.Join();
            return result ?? throw new Exception("Failed to run test in STA!");
        }
    }
}
espenalb
  • 538
  • 3
  • 17