【问题标题】:NUnit async test + RequiresSTA => await not returning on STA threadNUnit 异步测试 + RequiresSTA => 等待未在 STA 线程上返回
【发布时间】:2013-09-21 04:46:39
【问题描述】:

以下代码:

    [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

然后,在 new FrameworkElement() 上引发 InvalidOperationException。

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

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

【问题讨论】:

  • 当您回答自己的问题时,应将问题写成实际问题。
  • 写出问题和答案感觉很奇怪,但你是对的。完成:)

标签: c# wpf nunit async-await sta


【解决方案1】:

您可以使用 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();
  });
}

【讨论】:

    【解决方案2】:

    我设法解决了这个问题。但是,我确信在 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)

    【讨论】:

      猜你喜欢
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-13
      • 1970-01-01
      相关资源
      最近更新 更多