Подтвердить что ты не робот

NSubstitute - Получено для async - предупреждение "звонок не ожидается"

Я пытаюсь проверить, что асинхронный метод вызывается с правильными параметрами. Однако я получаю предупреждение:

"Поскольку этот вызов не ожидается, выполнение текущего метода продолжается до завершения вызова. Рассмотрите возможность применения оператора" ожидание "к результату вызова". Это предупреждение появляется в строке кода под комментарием //Assert (ниже).

Мой тест с использованием NSubstitute выглядит следующим образом:

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

Единый метод тестирования underTest.ExecuteAsync(request) вызывает ExecuteProcedureAsync и выполняет ожидание:

var ds = await DatabaseHelper.ExecuteProcAsync(dbParams);

В связи с тем, что с NSubstitute, Received() требуется после выполнения тестируемого устройства. В то время как в RhinoMocks вы можете ожидать для вызова, прежде чем тестируемое устройство будет выполнено. RhinoMocks может вернуть Task.FromResult(), в то время как NSubstitute не может.

Соответствующий эквивалент RhinoMocks:

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

        }

Я видел, что есть способ обхода, где вы можете добавить метод расширения для устранения проблемы:

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

    }
  }

Значение моей тестовой строки для NSubstitute может выполняться следующим образом, и предупреждение уходит:

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

Однако я предположил, что для этого должно быть лучшее решение?

4b9b3361

Ответ 1

Как только вы обновляетесь до версии 1.9.0 или выше, вы сможете использовать await без получения NullReferenceException.

Ответ 2

Всякий раз, когда предикат Received() становится слишком сложным или просто не соответствует NSubstitute, вы всегда можете захватить указанные аргументы, используя callbacks через When().Do() или .AndDoes(). Для вашего случая использования, который будет выглядеть примерно так.

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

Ответ 3

Ответ Джейк Гинниван объясняет, что для полученного ожидания не требуется, однако компилятор не понимает его.

Вы можете безопасно подавить предупреждение

 #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