Проверка принятых вызовов () для асинхронного метода
когда я запускаю следующий код:
[Test]
public async Task Can_Test_Update()
{
var response = await _controller.UpdateAsync(Guid.NewGuid());
response.Valid.Should().BeTrue();
_commands.Received().UpdateAsync(
Arg.Is<Something>(
l => l.Status == Status.Updated));
}
если я добавлю "await
" перед "_commands.Received().UpdateAsync
", он бросает пустой ссылкой исключение. Как я могу остановить это, или это await
Не надо?
6 ответов
Я нашел ответ здесь.
Received.InOrder(async () =>
{
await _Commands.UpdateAsync(Arg.Is<Lobby>(l => l.Status == Status.Updated));
});
когда NSubstitute видит асинхронный вызов, он автоматически создает завершенную задачу, поэтому await работает так, как вы ожидали бы в своем коде (и не бросает исключение NullReferenceException). В этом случае это будет задача, возвращенная из _commands.UpdateAsync(Status.Updated))
внутри метода тестирования.
на .Received()
call с другой стороны, проверяет, что был вызван метод async, который полностью синхронен, поэтому его не нужно ждать.
главное, что нужно помнить, это асинхронность методы возврата Task
. Вызов асинхронного метода и возврат задачи полностью синхронны, затем вы ждете Task
чтобы узнать, когда асинхронная операция, которую представляет задача, завершена.
по данным ответ при переполнении стека, начиная с nsubstitute версии 1.8.3 вы можете использовать await
и он будет работать, как ожидалось, а не бросать NullReferenceException.
Я только что попробовал это, как я был на версии 1.5.0 и получил исключение NullReferenceException, как вы описываете, но теперь я на последнем (1.10.0), он работает хорошо.
на Джейк Джинниван ответ правильно указывает, что для полученного await не требуется, однако компилятор этого не понимает и показывает
предупреждение CS4014: поскольку этот вызов не ожидается, выполнение текущий метод продолжается до завершения вызова. Считать применение оператора await к результату вызова.
самый простой обходной путь-подавить предупреждение
#pragma warning disable 4014 //for .Received await is not required, so suppress warning “Consider applying the 'await' operator”
_publisher.Received(totalNumber).MyMethod(Arg.Any<ParamType>());
#pragma warning restore 4014
когда я добавляю " ждать "перед" _commands.Полученный.)(UpdateAsync", возникает ошибка null reference
это потому, что когда ты не await
метод (Can_Test_Update
) может закончиться до того, как он фактически проверит нулевое значение, которое вы передаете методу, что означает, что тест заканчивается. У тебя расовое состояние. Когда ты await
on UpdateAsync
, метод фактически асинхронно ожидает завершения операции и UpdateAsync
получает шанс получить доступ к null вы переходите к нему.
чтобы устранить ошибку, просто поместите точку останова внутри UpdateAsync
и посмотреть, какое значение передается как null методу. Подозреваю!--6--> - это ваша проблема.
Если UpdateAsync-это метод stubbed, вам нужно вернуть пустую задачу, а не null. Вы не можете дождаться нулевой задачи.
пример:
receivedObject.Stub(s => s.Update(...)).Return(Task.FromResult(0));
редактировать
проблема в этой строке:
var mockService = Substitute.For<ICalculationServiceAsync>();
или более точно, когда вы вызываете его метод:
await _service.Calculate();
вы создаете макет службы, но вы не заглушаете метод. Я не уверен, как это сделать в Nunit (мы в основном используем Rhino, мне нужно проверить), но вам нужно заглушить ваш метод Calculate возвращает пустую задачу (Task.FromResult (0)). По умолчанию методы stubbed возвращают тип возврата по умолчанию, а значение по умолчанию (задача) равно null.
о ваша суть: DoSomethingAsync не должен быть асинхронным void. Полагаю, вы захотите дождаться казни.