[英]NUnit async test + RequiresSTA => await not returning on STA thread
The below code: 下面的代码:
[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();
}
Yields the following output: 产生以下输出:
9 - STA 9-STA
12 - MTA 12-MTA
And then, throws an InvalidOperationException on new FrameworkElement(). 然后,在新的FrameworkElement()上引发InvalidOperationException。
NUnit supports STA thread creation, now supports async tests, but it seems that it doesnt mix both modes by creating a MTA SynchronizationContext. NUnit支持STA线程创建,现在支持异步测试,但是它似乎没有通过创建MTA SynchronizationContext来混合两种模式。
How do I get this working? 我该如何工作? Any workaround ?
任何解决方法?
You can use the AsyncContext
from my AsyncEx
library , which was originally written to support async
unit tests before the unit test libraries supported them. 您可以使用我的
AsyncEx
库中的AsyncContext
,该库最初是为支持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();
});
}
I managed to fix this. 我设法解决了这个问题。 However, I'm sure that a post on stackoverflow would have avoided me quite a headache :) see my answer below.
但是,我敢肯定,关于stackoverflow的帖子会避免我很头疼:)参见下面的答案。
A really good article about SynchronizationContext (click here) just gave me the code (and the knowledge) I required. 一篇关于SynchronizationContext的非常好的文章(单击此处)只是给了我所需的代码(和知识)。
However, I had to tweak it a bit to avoid a deadlock on StaSynchronizationContext disposal, and to propagate the synchronization context inside the worker thread. 但是,我必须对其进行一些调整,以避免在StaSynchronizationContext处置方面出现死锁,并在工作线程内部传播同步上下文。
My test now looks like below: 我的测试现在如下所示:
[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();
}
}
Now outputs: 现在输出:
9 - STA 9-STA
12 - STA 12-STA
... problem solved ! ... 问题解决了 !
Download tweaked code here 在此处下载调整后的代码
* edit and disclaimer * Before having awaited something, your code will be running on the STA thread created by NUnit. *编辑和免责声明*在等待之前,您的代码将在NUnit创建的STA线程上运行。 (thread 9) After the first await, code will be running on the thread created by StaSynchronizationContext (thread 12): even if they're both STA they are not the same thread
(线程9)第一次等待后,代码将在StaSynchronizationContext创建的线程(线程12)上运行:即使它们都是STA, 它们也不是同一线程
Beware instanciating controls before await, and using them after. 在等待之前要提防实例化控件,然后再使用它们。 Just needs a bit more tweaking to switch directly to main thread (we could imagine a "using(await StaSynchronizationContext.Create())" which would make us switch on thread 12 at begining)
只是需要更多的调整才能直接切换到主线程(我们可以想象一个“ using(await StaSynchronizationContext.Create())”,这将使我们在开始时打开线程12)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.