Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSubstitute - Received for async - “call is not awaited”warning

I am trying to verify that an asynchronous method was called with the correct parameters. However, I get the warning:

"Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call". This warning appears on the line of code underneath the //Assert comment (below).

My test using NSubstitute is as follows:

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

The unit under test method underTest.ExecuteAsync(request) calls ExecuteProcedureAsync and performs the await:

var ds = await DatabaseHelper.ExecuteProcAsync(dbParams);

Due to the fact that with NSubstitute, the Received() is required after the execution of the unit under test. Whereas in RhinoMocks, you can expect for a call to occur before the unit under test is executed. RhinoMocks can return the Task.FromResult() whereas NSubstitute cannot.

The RhinoMocks equivalent that works is this:

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

        }

I have seen that there is a workaround where you can add an extension method to remove the issue:

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

    }
  }

Meaning my test line for NSubstitute can be executed as follows and the warning goes away:

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

However, I assumed there must be a better solution out there for this?

like image 979
JBond Avatar asked Jul 09 '15 13:07

JBond


People also ask

What happens if an async method is not awaited?

The call to the async method starts an asynchronous task. However, because no Await operator is applied, the program continues without waiting for the task to complete. In most cases, that behavior isn't expected.

What is a call from async?

An asynchronous method call is a method used in . NET programming that returns to the caller immediately before the completion of its processing and without blocking the calling thread.

How do you call async method without await?

However, just to address "Call an async method in C# without await", you can execute the async method inside a Task. Run . This approach will wait until MyAsyncMethod finish. await asynchronously unwraps the Result of your task, whereas just using Result would block until the task had completed.

Can we write async without await in C#?

C# Language Async-Await Returning a Task without awaitMethods that perform asynchronous operations don't need to use await if: There is only one asynchronous call inside the method. The asynchronous call is at the end of the method. Catching/handling exception that may happen within the Task is not necessary.


2 Answers

As soon as you update to version 1.9.0 or higher, you'll be able to use the await without receiving a NullReferenceException.

like image 130
Marcio Rinaldi Avatar answered Sep 25 '22 01:09

Marcio Rinaldi


Whenever the Received() predicate gets too complicated or just won't match with NSubstitute you can always capture the specified args using callbacks via When().Do() or .AndDoes(). For your use case that would go something like this

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...
like image 35
mkoertgen Avatar answered Sep 23 '22 01:09

mkoertgen