2015-07-09 20 views
18

Sto provando a verificare che un metodo asincrono è stato chiamato con i parametri corretti. Tuttavia, viene visualizzato l'avviso:NSubostato - Ricevuto per asincrono - avviso "chiamata non attesa"

"Poiché questa chiamata non è attesa, l'esecuzione del metodo corrente continua prima che la chiamata sia completata. Considerare l'applicazione dell'operatore" Attendi "al risultato della chiamata". Questo avviso appare sulla riga di codice sotto il commento //Assert (sotto).

mia prova utilizzando NSubstitute è la seguente:

[Test] 
public async Task SimpleTests() 
{ 
    //Arrange 
    var request = CreateUpdateItemRequest(); 

    databaseHelperSub.ExecuteProcAsync(Arg.Any<DatabaseParams>()).Returns(Task.FromResult((object)null)); 

    //Act  
    await underTest.ExecuteAsync(request); 

    //Assert 
    databaseHelperSub.Received().ExecuteProcAsync(Arg.Is<DatabaseParams>(
    p => p.StoredProcName == StoredProcedureName 
     && p.Parameters[0].ParameterName == "Param1" 
     && p.Parameters[0].Value.ToString() == "Value1" 
     && p.Parameters[1].ParameterName == "Param2" 
     && p.Parameters[1].Value.ToString() == "Value2")); 
} 

L'unità sottoposta metodo di prova underTest.ExecuteAsync(request) chiamate ExecuteProcedureAsync ed esegue l'attendono:

var ds = await DatabaseHelper.ExecuteProcAsync(dbParams); 

causa del fatto che con NSubstitute, la Ricevuto() è richiesto dopo l'esecuzione dell'unità in prova. Considerando che in RhinoMocks, è possibile aspettare per una chiamata prima che venga eseguita l'unità in prova. RhinoMocks può restituire Task.FromResult() mentre NSubstitute non può.

Il RhinoMocks equivalente che funziona è questo:

[Test] 
     public async Task SimpleTest() 
     { 
      // Arrange 
      var request = new UpdateItemRequest(); 

      databaseHelperMock.Expect(m => m.ExecuteProcAsync(Arg<DatabaseParams>.Matches(
       p => p.StoredProcName == StoredProcedureName 
        && p.Parameters[0].ParameterName == "Param1" 
        && p.Parameters[0].Value.ToString() == "Value1" 
        && p.Parameters[1].ParameterName == "Param2" 
        && p.Parameters[1].Value.ToString() == "Value2 
       ))).Return(Task.FromResult<object>(null)); 

      // Act 
      await underTest.ExecuteAsync(request); 

     } 

ho visto che c'è una soluzione in cui è possibile aggiungere un metodo di estensione per rimuovere il problema:

public static class TestHelper 
    { 
    public static void IgnoreAwait(this Task task) 
    { 

    } 
    } 

Significato mia linea di test per NSubstitute può essere eseguito come segue e l'avviso scompare:

databaseHelperSub.Received().ExecuteProcAsync(Arg.Is<DatabaseParams>(
     p => p.StoredProcName == StoredProcedureName 
      && p.Parameters[0].ParameterName == "Param1" 
      && p.Parameters[0].Value.ToString() == "Value1" 
      && p.Parameters[1].ParameterName == "Param2" 
      && p.Parameters[1].Value.ToString() == "Value2")).IgnoreAwait(); 
    } 

Tuttavia, ho presunto che ci deve essere una soluzione migliore là fuori per questo?

+0

Questo è un compilatore * * avvertimento dicendo che ti sei dimenticato di mettere un 'await' prima di un metodo asincrono. Perché non metti semplicemente "aspetta" nella riga dopo "// Assert"? –

+2

Se si mette in attesa prima della chiamata. Il test ha esito negativo in quanto riceve un'eccezione di riferimento null. – JBond

+3

NSubstitute non ha un modo migliore di gestirlo al momento. Vedi la spiegazione di Jake qui: http://stackoverflow.com/a/31021430/906 Potrebbe valere una modifica NSub, ho creato un problema qui: https://github.com/nsubstitute/NSubstitute/issues/190 –

risposta

15

Non appena si aggiorna alla versione 1.9.0 o superiore, sarete in grado di utilizzare il await senza ricevere un NullReferenceException.

+0

Hai idea di quando la versione 1.8.3 potrebbe essere rilasciata? Sto avendo questo problema al momento – levelnis

+0

non lo so. Dovresti chiedere a David Tchepak (tramite https://github.com/nsubstitute/NSubstitute/issues forse). È il manutentore del NSubstitute. –

+1

@levelnis Solo così sei consapevole. V1.9.0 di NSubstitute è stato rilasciato. Che contiene miglioramenti che risolveranno il problema in questa domanda di overflow dello stack. – JBond

5

Ogni volta che il predicato Received() diventa troppo complicato o semplicemente non corrisponderanno con NSubstitute è sempre possibile catturare i args specificati utilizzando callbacks via When().Do() o .AndDoes(). Per il vostro caso d'uso che sarebbe andato qualcosa come questo

DatabaseParams receivedParms = null; 
databaseHelperSub.ExecuteProcAsync(Arg.Any<DatabaseParams>()) 
    .Returns(Task.FromResult((object)null)) 
    .AndDoes(x => receivedParms = x.Arg<DatabaseParams>); 

//Act  
await underTest.ExecuteAsync(request); 

//Assert 
receivedParms.Should().NotBeNull(); 
// assert your parms... 
0

Il Jake Ginnivan answer spiega che per Received await non è richiesto, tuttavia il compilatore non lo capisce.

È possibile eliminare in modo sicuro l'avviso

#pragma warning disable 4014 //for .Received await is not required, so suppress warning “Consider applying the 'await' operator” 
    _service.Received(totalNumber).MyMethod(Arg.Any<ParamType>()); 
#pragma warning restore 4014