2017-05-06 126 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)'。 –

相關問題