2017-05-06 128 views
-1

默认情况下,单元测试不捕获在其运行的SynchronizationContext,所以如果你写的东西,如:为什么ConfigureAwait(true)在单元测试中不起作用?

[TestMethod] 
public async Task AwaitThreadSwitch() 
{ 
    WriteThread(); 
    await Do(); 
    WriteThread(); 
} 

private Task Do() 
{ 
    return Task.Run(() => 
    { 
     WriteThread(); 
     Thread.Sleep(50); 
    }); 
} 

private void WriteThread() 
{ 
    Debug.WriteLine($"CURRENT THREAD: {Thread.CurrentThread.ManagedThreadId}"); 
} 

你获得如下输出:

CURRENT THREAD: 8 
CURRENT THREAD: 6 
CURRENT THREAD: 6 

这是很正常的:一旦await被调用并返回,流程不会返回到原始线程。现在

,如果我写的测试方法是这样的:

[TestMethod] 
public async Task AwaitThreadSwitch() 
{ 
    WriteThread(); 
    await Do().ConfigureAwait(true); // <-- note this change 
    WriteThread(); 
} 

我希望:

CURRENT THREAD: 8 
CURRENT THREAD: 6 
CURRENT THREAD: 8 // <-- back to the main Thread 

相反,我得到的第一个测试的结果相同。

为什么不将执行编组回到测试方法的主线程?

+0

'ConfigureAwait'与线程无关。一点都没有。任何线程都可以执行任何任务。异步代码可以在任何线程上的“await”后重新开始,始终如此。这是迄今为止“Task”API的头号误解。我不知道它来自哪里。 –

+3

@BenjaminHodgson:我不同意你的描述。确实,作为一个抽象,“SynchronizationContext”并不一定必须完全对应于线程。但是,这并不意味着它与他们完全没有任何关系。在Winforms或WPF的常见情况下,上下文实际上与特定的线程绑定,“await”_will_实际上总是在该线程上恢复(除非另有指示),并且事实上可以考虑线程代码正在执行。也许这种“误解”来自它并不是真正的一个。 –

回答

3

您似乎误解了为什么测试不会回到第一个示例中的主线程。这并不是因为在某个地方隐含设置了ConfigureAwait(false)。相反,这是因为没有同步上下文

您的两个测试实际上是完全相同的。调用ConfigureAwait(true)与根本不调用它没有区别。只是没有上下文可以返回,并且默认的同步上下文行为只是在同一个线程中继续。

所以,这就是你在这两个测试中看到的。因为两个测试都是一样的。

+0

但是,如果我为我的单元测试设置了'SynchronizationContext',它们将不会再一样了,对吗? –

+1

@MassimilianoKraus:不,你错了。你的单元测试实际上是相同的。即使你设置了一个'SynchronizationContext'。为了让它们不同,必须调用'ConfigureAwait(false)',而不是'ConfigureAwait(true)'。 –

相关问题