2012-12-29 17 views
18

下異步xUnit.net測試與帶有async修改一個lambda未能通過報告,沒有異常被拋出:如何處理xUnit中的Tasks引發的異常.net的Assert.Throws <T>?

[Theory, AutoWebData] 
    public async Task SearchWithNullQueryThrows(
     SearchService sut, 
     CancellationToken dummyToken) 
    { 
     // Fixture setup 
     // Exercise system and verify outcome 
     Assert.Throws<ArgumentNullException>(async() => 
      await sut.SearchAsync(null, dummyToken)); 
     // Teardown 
    } 

要確保一個ArgumentNullException實際上是扔我明確地使用了try-catch塊。它的工作,但生成的代碼是不乾淨的(與第一次測試):

[Theory, AutoWebData] 
public async Task SearchWithNullQueryThrows(
    SearchService sut, 
    CancellationToken dummyToken) 
{ 
    // Fixture setup 
    var expected = typeof(ArgumentNullException); 
    Type actual = null; 
    // Exercise system 
    try 
    { 
     await sut.SearchAsync(null, dummyToken); 
    } 
    catch (ArgumentNullException e) 
    { 
     actual = e.GetType(); 
    } 
    // Verify outcome 
    Assert.Equal(expected, actual); 
    // Teardown 
} 

爲什麼Assert.Throws<T>lambda標有async修改失敗?

+3

這是一個已知的問題:http://xunit.codeplex.com/workitem/9799 – DaveShaw

+0

+1它似乎在快照'03e3be9a6781'中被修復,快照'16883cb2351f'之前已經關聯了2.0.0-alpha版本。但是,在使用NuGet Package Manager更新解決方案後,它仍然不起作用。 –

回答

33

更新

這已經解決了的xUnit 2,增加的Assert.ThrowsAsync


我懷疑Assert.Throwsasync知曉。我建議用xUnit團隊提出這個問題,建議添加ThrowsAsync

一種async代表在這種情況下返回TaskTask<T>,並且ArgumentNullException不拋出直接委託的;相反,它被放置在TaskTask.Exception.InnerException)。 Assert.Throws正期望將異常直接拋出委託,而不是放在返回值的屬性上。

您可以創建自己的AssertEx.ThrowsAsync這樣:

public static async Task ThrowsAsync<TException>(Func<Task> func) 
{ 
    var expected = typeof(TException); 
    Type actual = null; 
    try 
    { 
    await func(); 
    } 
    catch (Exception e) 
    { 
    actual = e.GetType(); 
    } 
    Assert.Equal(expected, actual); 
} 

它可以作爲這樣的:

[Theory, AutoWebData] 
public async Task SearchWithNullQueryThrows(
    SearchService sut, 
    CancellationToken dummyToken) 
{ 
    // Fixture setup 
    // Exercise system and verify outcome 
    await AssertEx.ThrowsAsync<ArgumentNullException>(async() => 
     await sut.SearchAsync(null, dummyToken)); 
    // Teardown 
} 

我使用MSTest的類似的方法。

+0

工作:)謝謝! –

+0

我稍微修改了你的代碼,因爲我相信它只存在於'ArgumentNullException'中,所以會一直到'Assert'。另一件值得考慮的事情是,最初的'Assert.Throws' *返回異常(例如,您也可以測試異常消息)。 – Benjol

+0

參見https://gist.github.com/Haacked/4616366 – Benjol

2

如果您還需要返回例外,以驗證它那麼這可能是有用的:

public static async Task<Exception> AssertThrowsAsync<TException>(Func<Task> func) 
    { 
     var expected = typeof (TException); 
     Exception exception = null; 
     Type actual = null; 
     try 
     { 
      await func(); 
     } 
     catch (Exception e) 
     { 
      actual = e.GetType(); 
      exception = e; 
     } 
     Assert.NotNull(exception); 
     Assert.Equal(expected, actual); 
     return exception; 
    }