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

4

9

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();
}
Truancy answered 14/7, 2010 at 12:46 Comment(2)
Which version of Visual studio?Chloride
Visual Studio 2008 with option of moving to 2010 if necessaryTruancy
P
7

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)));
Parrott answered 14/7, 2010 at 14:24 Comment(4)
In this case, the action would be waiting on all handles. I'll update my answer to show an example unit test and how this all fits together.Parrott
So it requires changes in the productive code? It can't be fixed in the unit test only?Antemortem
Oh, I'm sorry... I think the premise is that you're rigging up wait handles inside your test to test things like callbacks or threaded stuff.Parrott
Oh, I haven't had that problem yet... sounds like you need some kind of collaborator that checks the current thread state and executes the OnMtaThread action when necessary. Better yet, post a question with your context and errors!Parrott
E
2

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>
Ellora answered 23/5, 2012 at 3:38 Comment(0)
C
0

For my Visual Studio 2010 only the following configuration made tests work.

<Execution>
     <ExecutionThread apartmentState="1" />
</Execution>
Collapse answered 28/8, 2012 at 13:33 Comment(0)
T
0

For VS2008 the instructions are slightly different compared to VS2010. For VS2008, edit the testrunconfig file, and add the following to the TestRunConfiguration element:

<ExecutionThread apartmentState="MTA" />
Tonguing answered 4/6, 2014 at 14:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.