2017-06-01 57 views
2

已經閱讀一些Stephen Cleary我發現這個職位:如何單元測試異步/等待示例?

http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

有了這個例子:

// My "library" method. 
public static async Task<JObject> GetJsonAsync(Uri uri) 
{ 
    using (var client = new HttpClient()) 
    { 
    var jsonString = await client.GetStringAsync(uri); 
    return JObject.Parse(jsonString); 
    } 
} 

// My "top-level" method. 
public async void Button1_Click(...) 
{ 
    var json = await GetJsonAsync(...); 
    textBox1.Text = json; 
} 

如何將一個把這個代碼轉換成一個NUnit的單元測試,表現出同樣的解決同樣的問題?

我將這段代碼作爲一個單元測試,但它的行爲與接口示例代碼不一樣 - 除非我誤解了這篇文章。

// My "library" method. 
public static async Task<JObject> GetJsonAsync(Uri uri) 
{ 
    using (var client = new HttpClient()) 
    { 
    var jsonString = await client.GetStringAsync(uri); 
    return JObject.Parse(jsonString); 
    } 
} 

// My "top-level" method. 
[Test] 
public async void TestButton1_Click(...) 
{ 
    var json = await GetJsonAsync(...); 
    var gotOutput = json; 
} 

有沒有斷言,因爲這會後來。

+0

你會在上面的代碼來測試?沒有必要讓事情過於複雜。進行異步測試並鍛鍊測試中的主題。 – Nkosi

+0

我想展示文章中所示的死鎖,但是當我將示例代碼放入單元測試中時,我沒有看到發生這種情況。我將修改帖子以顯示我認爲單元測試代碼的樣子。 –

+0

'TestButton1_Click'很可能是一個事件處理程序。這是實際允許'async void'的情況之一。在你的測試中,它不是一個事件處理程序,而僅僅是一個正常的異步無效方法,它們被火和遺忘了。因此,測試工具不會引發斷言 – Nkosi

回答

5

該死鎖有兩個組件:異步代碼阻塞和單線程上下文。

粘貼的代碼示例在異步代碼上沒有阻塞(沒有.Result)。它看起來像你複製了而不是死鎖的樣本。

要重現死鎖,您需要同時阻塞異步代碼,並提供單線程上下文。 NUnit確實有一個單線程的上下文,它適用於某些場景。細節已經改變了幾次,但我敢肯定,他們結束了應用上下文async void方法,所以我認爲這會發生死鎖:

[Test] 
public async void TestButton1_Click(...) 
{ 
    var json = GetJsonAsync(...).Result; 
} 

您可以檢查是否NUnit的是通過提供上下文從測試中的斷點處讀取SynchronizationContext.Current。如果不是,那麼你可以提供像AsyncContext in my AsyncEx library上下文自己:

[Test] 
public void TestButton1_Click(...) 
{ 
    var json = AsyncContext.Run(() => GetJsonAsync(...).Result); 
} 
+0

是的;我的錯。我確實複製了非阻塞代碼。它做得很匆忙。在繼續之前,我要消化這個。 –