2012-12-29 6 views
18

Der folgende asynchrone xUnit.net Test mit einem lambda mit dem Modifikator nicht async gekennzeichnet durch die Berichterstattung, dass keine Ausnahme ausgelöst wurde:Wie behandelt man Ausnahmen, die von Tasks in xUnit .nets Assert.Throws <T> ausgelöst werden?

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

Um sicherzustellen, dass ein ArgumentNullException ich explizit einen try-catch Block verwendete tatsächlich geworfen wird. Es funktionierte, aber der resultierende Code nicht sauber ist (im Vergleich zum ersten Test):

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

Warum die Assert.Throws<T> mit den lambda schlägt mit dem async Modifikator markiert?

+3

Dies ist ein bekanntes Problem: http://xunit.codeplex.com/workitem/9799 – DaveShaw

+0

+1 Es scheint in Snapshot '03e3be9a6781' behoben zu sein, der vor dem Snapshot' 16883cb2351f' liegt, wo Release '2.0.0-alpha' zugeordnet wurde. Nach dem Aktualisieren der Lösung mit NuGet Package Manager funktioniert es jedoch immer noch nicht. –

Antwort

33

aktualisieren

Dieses 2, mit dem Zusatz von Assert.ThrowsAsync in xUnit gelöst wurde.


ich zu ahnen, dass Assert.Throws nicht async -Aware ist. Ich empfehle, dieses Problem mit dem xUnit-Team anzusprechen, was darauf hinweist, dass eine ThrowsAsync hinzugefügt werden muss.

Ein async Delegierten in diesem Fall kehrt Task oder Task<T> und die ArgumentNullException nicht direkt aus dem Delegierten geworfen; stattdessen wird es auf die Task (Task.Exception.InnerException) platziert. Assert.Throws erwartet, dass die Ausnahme direkt aus dem Delegat herausgeworfen wird und nicht in einer Eigenschaft des Rückgabewerts platziert wird.

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

, die als solche verwendet werden können:

Sie können Ihre eigene AssertEx.ThrowsAsync als solche erstellen

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

ich einen ähnlichen Ansatz in MSTest verwenden.

+0

Das hat funktioniert :) Danke! –

+0

Ich habe Ihren Code etwas modifiziert, da ich glaube, dass es nur 'ArgumentNullException' jemals so weit gehen würde wie 'Assert'. Eine andere Sache, die eine Überlegung wert ist, ist, dass das Original 'Assert.Throws' * die Ausnahme zurückgibt (so dass Sie beispielsweise auch eine Ausnahmebedingungsnachricht testen können). – Benjol

+0

Siehe auch https://gist.github.com/Haacked/4616366 – Benjol

2

Wenn Sie auch die Ausnahme zurückgeben müssen, sie zu überprüfen, dann könnte dies nützlich sein:

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