Проверка принятых вызовов () для асинхронного метода

когда я запускаю следующий код:

[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. Полагаю, вы захотите дождаться казни.