Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use WaitHandler.WaitAll in MSTest without STA warnings?

Is there a way to unit test WaitHandle.WaitAll() when using Visual Studio's built-in unit testing solution. When I try and run a test that uses this function within Visual Studio the test fails and when examining the test results the following error is displayed:

WaitAll for multiple handles on a STA thread is not supported

I'd like to be able to unit test the use of WaitAll() since an increasing amount of my API's code base is now moving to an IAsyncResult pattern as opposed to other means of doing multi-threaded operations.

Edit

Based on Anthony's suggestion here is a simple helper method that can be used to invoke such code in a unit test environment:

public static void TestInMTAThread(ThreadStart info)
{
    Thread t = new Thread(info);
    t.SetApartmentState(ApartmentState.MTA);
    t.Start();
    t.Join();
}
like image 317
RobV Avatar asked Jul 14 '10 12:07

RobV


People also ask

How do I run a MSTest unit test?

To run MSTest unit tests, specify the full path to the MSTest executable (mstest.exe) in the Unit Testing Options dialog. To call this dialog directly from the editor, right-click somewhere in the editor and then click Options.

How do you add MSTest to a project?

On the Create a new project page, type unit test into the search box. Select the project template for the test framework that you want to use, for example MSTest Test Project or NUnit Test Project, and then select Next. On the Configure your new project page, enter a name for your project, and then select Create.


2 Answers

You may have two problems. The first is the one you stated: You cannot wait on multiple Wait Handles in an STA thread (the MSTest thread apartment state). We can fix that with a manually created MTA thread.

public static void OnMtaThread(Action action)
{
    var thread = new Thread(new ThreadStart(action));
    thread.SetApartmentState(ApartmentState.MTA);
    thread.Start();
    thread.Join();
}

The environment also has a maximum wait handle limit. In .NET 2.0, it appears to be hard coded to 64. Waiting on more than the limit will produce a NotSupportedException. You can use an extension method to wait on all wait handles in chunks.

public static void WaitAll<T>(this List<T> list, TimeSpan timeout)
    where T : WaitHandle
{
    var position = 0;
    while (position <= list.Count)
    {
        var chunk = list.Skip(position).Take(MaxWaitHandles);
        WaitHandle.WaitAll(chunk.ToArray(), timeout);
        position += MaxWaitHandles;
    }
}

And you'd rig them together like this in your test (in the Act or Assert part of the test)

OnMtaThread(() => handles.WaitAll(Timespan.FromSeconds(10)));
like image 159
Anthony Mastrean Avatar answered Nov 09 '22 13:11

Anthony Mastrean


In Visual Studio 2008 & 2010 you can change your .testsettings file to run the tests under an MTA thread by adding <ExecutionThread apartmentState="MTA" />.

<Execution>
     <ExecutionThread apartmentState="MTA" />
</Execution>
like image 44
row1 Avatar answered Nov 09 '22 13:11

row1