2012-12-29 6 views
18

Poniższy asynchroniczny xUnit.net Test z lambda oznaczonego modyfikatora async nie zgłaszając, że żaden wyjątek:Jak obsłużyć wyjątki wyrzucane przez zadania w pliku xUnit .net's 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 
    } 

Aby upewnić się, że ArgumentNullException jest faktycznie rzucony jawnie użył try-catch blok. Udało się, jednak uzyskany kod nie jest czysty (w porównaniu do pierwszego testu):

[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 
} 

Dlaczego Assert.Throws<T> z lambda oznaczone modyfikatora async nie powiedzie?

+3

To znany problem: http://xunit.codeplex.com/workitem/9799 – DaveShaw

+0

+1 It wydaje się być naprawione w migawce '03e3be9a6781', która jest przed migawką' 16883cb2351f', gdzie zostało wydane wydanie '2.0.0-alpha'. Jednak nadal nie działa po zaktualizowaniu rozwiązania za pomocą NuGet Package Manager. –

Odpowiedz

33

Aktualizacja

ten został rozwiązany w xUnit 2, z dodatkiem Assert.ThrowsAsync.


jestem podejrzewać, że nie jest Assert.Throwsasync -aware. Polecam zgłaszanie tego problemu zespołowi xUnit, sugerując dodanie numeru ThrowsAsync.

async delegat w tym przypadku jest zwrócenie Task lub Task<T>, a ArgumentNullException nie wyrzucono delegata bezpośrednio; zamiast tego jest umieszczony na Task(). Assert.Throws oczekuje, że wyjątek zostanie wyrzucony bezpośrednio z uczestnika, a nie umieszczony na właściwości wartości zwracanej.

można stworzyć swój własny AssertEx.ThrowsAsync jako takie:

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); 
} 

które mogą być używane jako takie:

[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 
} 

używam podobnego podejścia w MSTest.

+0

To zadziałało :) Dziękujemy! –

+0

Ja nieznacznie zmodyfikowałem twój kod, ponieważ uważam, że tylko "ArgumentNullException" kiedykolwiek dotarłby do "Assert". Inną rzeczą wartą rozważenia jest to, że oryginalny 'Assert.Throws' * zwraca * wyjątek (tak, że możesz na przykład przetestować wyjątek). – Benjol

+0

Zobacz także https://gist.github.com/Haacked/4616366 – Benjol

2

Jeśli trzeba także zwrócić wyjątek w celu sprawdzenia go wtedy może to być przydatne:

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; 
    }