NUnit异步测试+ RequiresSTA =>等待不在STA线程上返回

时间:2013-09-16 22:07:40

标签: c# wpf nunit async-await sta

以下代码:

    [RequiresSTA]
    [Test]
    public async Task TestSta()
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" - "+Thread.CurrentThread.GetApartmentState());
        // *** await something here ***
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" - "+Thread.CurrentThread.GetApartmentState());
        new FrameworkElement();
    }

产生以下输出:

9 - STA

12 - MTA

然后,在新的FrameworkElement()上抛出InvalidOperationException。

NUnit支持STA线程创建,现在支持异步测试,但似乎它不会通过创建MTA SynchronizationContext来混合这两种模式。

我如何让这个工作?任何解决方法?

2 个答案:

答案 0 :(得分:3)

您可以使用AsyncContext from my AsyncEx library,它最初用于在单元测试库支持之前支持async单元测试。

[RequiresSTA]
[Test]
public Task TestSta()
{
  AsyncContext.Run(async () =>
  {
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" - "+Thread.CurrentThread.GetApartmentState());
    // *** await something here ***
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" - "+Thread.CurrentThread.GetApartmentState());
    new FrameworkElement();
  });
}

答案 1 :(得分:0)

我设法解决了这个问题。但是,我确信stackoverflow上的帖子会让我非常头疼:)请看下面的答案。

A really good article about SynchronizationContext (click here)刚刚给了我所需的代码(和知识)。

但是,我必须稍微调整它以避免StaSynchronizationContext处理时出现死锁,并在工作线程内传播同步上下文。

我的测试现在如下所示:

    [Test]
    [RequiresSTA]
    public async Task DoSomeUITest()
    {
        using (new StaSynchronizationContext())
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + Thread.CurrentThread.GetApartmentState());
            // *** await something here ***
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " - " + Thread.CurrentThread.GetApartmentState());
            new FrameworkElement();
        }
    }

现在输出:

9 - STA

12 - STA

......问题解决了!

Download tweaked code here

*编辑和免责声明* 在等待某事之前,您的代码将在NUnit创建的STA线程上运行。 (主题9) 在第一次等待之后,代码将在StaSynchronizationContext(线程12)创建的线程上运行:即使它们都是STA ,它们也不是同一个线程

在等待之前注意实施控制,并在之后使用它们。 只需要更多调整就可以直接切换到主线程(我们可以设想“使用(等待StaSynchronizationContext.Create())”这将使我们在开始时切换线程12)