web-dev-qa-db-fra.com

NSubstitute - Reçu pour async - avertissement «l'appel n'est pas attendu»

J'essaie de vérifier qu'une méthode asynchrone a été appelée avec les paramètres corrects. Cependant, je reçois l'avertissement:

"Parce que cet appel n'est pas attendu, l'exécution de la méthode actuelle se poursuit avant la fin de l'appel. Envisagez d'appliquer l'opérateur 'wait' au résultat de l'appel". Cet avertissement apparaît sur la ligne de code sous le commentaire //Assert (Ci-dessous).

Mon test en utilisant NSubstitute est le suivant:

[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é sous la méthode de test underTest.ExecuteAsync(request) appelle ExecuteProcedureAsync et effectue l'attente:

var ds = await DatabaseHelper.ExecuteProcAsync(dbParams);

En raison du fait qu'avec NSubstitute, le Received () est requis après l'exécution de l'unité testée. Alors que dans RhinoMocks, vous pouvez attendre pour qu'un appel se produise avant l'exécution de l'unité testée. RhinoMocks peut retourner le Task.FromResult () alors que NSubstitute ne le peut pas.

L'équivalent de RhinoMocks qui fonctionne est le suivant:

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

        }

J'ai vu qu'il existe une solution de contournement où vous pouvez ajouter une méthode d'extension pour supprimer le problème:

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

    }
  }

Cela signifie que ma ligne de test pour NSubstitute peut être exécutée comme suit et l'avertissement disparaît:

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

Cependant, j'ai supposé qu'il devait y avoir une meilleure solution pour cela?

23
JBond

Dès que vous mettez à jour vers la version 1.9.0 ou supérieure, vous pourrez utiliser le await sans recevoir un NullReferenceException.

21
Marcio Rinaldi

Chaque fois que le prédicat Received() devient trop compliqué ou ne correspond tout simplement pas à NSubstitute, vous pouvez toujours capturer les arguments spécifiés en utilisant callbacks via When().Do() ou .AndDoes(). Pour votre cas d'utilisation qui irait quelque chose comme ça

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...
7
mkoertgen

La réponse de Jake Ginnivan explique que l'attente reçue n'est pas requise, mais que le compilateur ne la comprend pas.

Vous pouvez supprimer l'avertissement en toute sécurité

 #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