Ответ 1
Как только вы обновляетесь до версии 1.9.0 или выше, вы сможете использовать await
без получения NullReferenceException
.
Я пытаюсь проверить, что асинхронный метод вызывается с правильными параметрами. Однако я получаю предупреждение:
"Поскольку этот вызов не ожидается, выполнение текущего метода продолжается до завершения вызова. Рассмотрите возможность применения оператора" ожидание "к результату вызова". Это предупреждение появляется в строке кода под комментарием //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();
}
Однако я предположил, что для этого должно быть лучшее решение?
Как только вы обновляетесь до версии 1.9.0 или выше, вы сможете использовать await
без получения NullReferenceException
.
Всякий раз, когда предикат 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...
Ответ Джейк Гинниван объясняет, что для полученного ожидания не требуется, однако компилятор не понимает его.
Вы можете безопасно подавить предупреждение
#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