2015-01-20 12 views
17

Secondo this discussion, non ci dovrebbe essere alcuna differenza tra i due metodi seguenti:Perché i test di unità asincrone falliscono quando le parole chiave asincrone/attese non vengono utilizzate?

public async Task Foo() 
{ 
    await DoSomethingAsync(); 
} 

public Task Foo() 
{ 
    return DoSomethingAsync(); 
} 

In realtà, sembrerebbe che per i metodi molto semplici, l'invocazione senza Async/attendono parole chiave sarebbe preferibile, come rimuovono alcuni overhead.

Tuttavia, questo a quanto pare non funziona sempre nei test di unità.

MSTest

[TestClass] 
public class AsyncTest 
{ 
    [TestMethod] 
    public async Task Test1() 
    { 
     await Task.Delay(0); 
    } 

    [TestMethod] 
    public Task Test2() 
    { 
     return Task.Delay(0); 
    } 
} 

NUnit

[TestFixture] 
public class AsyncTest 
{ 
    [Test] 
    public async Task Test1() 
    { 
     await Task.Delay(0); 
    } 

    [Test] 
    public Task Test2() 
    { 
     return Task.Delay(0); 
    } 
} 

xUnit

public class AsyncTest 
{ 
    [Fact] 
    public async Task Test1() 
    { 
     await Task.Delay(0); 
    } 

    [Fact] 
    public Task Test2() 
    { 
     return Task.Delay(0); 
    } 
} 
  • In tutti i casi, passa Test1.
  • In MSTest, Test2 rivela nel test runner, ma non viene eseguito.
  • In NUnit, Test2 viene ignorato, con il messaggio:

    Metodo di prova ha tipo di ritorno non vuoto, ma nessun risultato è atteso

  • In xUnit, Test2 passaggi.

Dal momento che i compiti sono ancora awaitable in ogni caso, che cosa si tratta la parola async che colpisce i corridori di prova NUnit e MSTest? Forse qualche problema di riflessione?

+1

In realtà, c'è [una certa differenza] (http://stackoverflow.com/a/21082631/1768303) tra 'Test1' e' Test2' :) – Noseratio

+1

@Noseratio - Grazie! –

risposta

8

suona come quei corridori di prova possono fare uso di riflessione per verificare se il metodo di ritorno Task davvero è un metodo asincrono. Ciò non significa che il metodo si comporterebbe in modo diverso se fossero eseguiti - ma non vengono semplicemente eseguiti.

E 'come dire che:

public string Name { get; set; } 

è equivalente a:

private string name; 
public Name { get { return name; } set { name = value; } } 

Sono logicamente lo stesso in termini di comportamento, ma se si cerca abbastanza duro con la riflessione, si può dire la differenza. In questo caso particolare ci sono altre differenze più sottili, ma si applica lo stesso principio generale.

Sembra che nel codice NUnit corrente (al momento della stesura di questo) il rilevamento è in AsyncInvocationRegion.cs.

Bisogna ammettere che sono almeno insolito a dare una prova di unità che restituisce un Task ma senza usare un metodo asincrono - ma tutt'altro che impossibile.

+1

Capisco. Quindi NUnit si aspetta che il metodo sia stato decorato con 'AsyncStateMachineAttribute' dal compilatore. Immagino che lo spieghi. MSTest probabilmente sta facendo qualcosa di simile. –

+2

@MattJohnson: Ovviamente potresti aggiungere quell'attributo da te, sospetto - solo per ingannarlo. Forse vale la pena provare solo per vedere cosa fa MSTest ... –

+2

Sì. Aggiunto '[AsyncStateMachine (typeof (Task))]' e ora passa sotto MSTest e NUnit. Anche se penso che rimarrò solo asincrono/attendo parole chiave. :) –