Ожидание задачи, запущенной другим методом

Мне нужно убедиться, что задача завершена, прежде чем переходить к остальной части моего модульного теста.

Но это задача, которая ожидается внутри другого метода (я выполняю модульное тестирование метода).

Я пробовал ждать задачи или вызывать task.Wait(), но каждый раз тест не работает.

Фактический метод выглядит так:

private async void DoStuff(long idToLookUp)
{
    IOrder order = await orderService.LookUpIdAsync(idToLookUp);   

    OtherStuff = false;
}    

Я пытаюсь выполнить модульное тестирование следующим образом:

[TestMethod]
public void TestDoStuff()
{
    //+ Arrange
    var lookupTask = Task<IOrderableTest>.Factory.StartNew(() => validOrder);
    orderService.LookUpIdAsync(Arg.Any<long>()).Returns(lookupTask);

    //+ Act
    myViewModel.DoStuff();
    await lookupTask;

    //+ Assert
    myViewModel.OtherStuff.Should().BeFalse();
}

То, как это терпит неудачу, очень бесполезно. В результате другой тест завершается сбоем с сообщением «Процесс агента был остановлен во время выполнения теста». (Из того, что я могу прочитать, это означает, что фоновый поток выдал исключение во время выполнения теста.)

Поэтому мне интересно, как заставить мой код ждать завершения этого модульного теста.

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

ПРИМЕЧАНИЕ. Я ориентируюсь на .NET 4.0, используя пакет ansyc.


person Vaccano    schedule 10.01.2013    source источник
comment
Не создавайте async voids; вы не можете ждать их.   -  person SLaks    schedule 11.01.2013
comment
@SLaks - Увы, для многих вещей требуются недействительные сигнатуры методов. (Команды — одна из них. Я предполагаю, что у меня может быть два метода для каждого из моих вызовов команд, но это кажется беспорядочным.)   -  person Vaccano    schedule 11.01.2013
comment
@Vaccano В таких случаях следует быть предельно осторожным. Потому что в большинстве случаев это означает, что async просто не будет работать с этими вещами. Очень редко используется async void правильное решение.   -  person svick    schedule 11.01.2013


Ответы (2)


У вас никогда не должно быть метода void, возвращающего async, если только он не будет обработчиком событий (в этом случае у вас нет выбора). Когда async метод является void, вы не можете знать, когда он завершится.

Метод должен возвращать Task (а не Task<T>, если он не имеет значимого результата, а просто указывает на то, что он завершается).

Как только он вернет Task, вы можете await его протестировать или использовать Wait, если это уместно.

Вы ожидаете выполнения одной из задач, от которых зависит метод, но это не означает, что он завершил свой собственный код. Это означает, что в вашем тесте возникло состояние гонки.

person Servy    schedule 10.01.2013

Этот вызов await myViewModel.DoStuff(); возвращается, как только нажимается ключевое слово await (ну, если только он не завершается очень быстро). Кроме того, как упомянул Слакс, вы не можете ждать метода возврата void.

Затем вы ждете var lookupTask = Task<IOrderableTest>.Factory.StartNew(() => validOrder);, который, похоже, мало что делает, кроме возврата IOrderableTest .

Кроме того, я не думаю, что вам следует делать await lookupTask, это снова вернется к вызывающей стороне, в этом случае TestRunner не ожидает / не может этого ожидать.

Вместо этого следует использовать lookupTask.Wait() (это блокирующий вызов); И убедитесь, что для завершения myViewModel.DoStuff(); также требуется достаточно времени.

Обзор:

private async Task DoStuff(long idToLookUp)
{
    IOrder order = await orderService.LookUpIdAsync(idToLookUp);   

    OtherStuff = false;
    return;
}

....

 var task = myViewModel.DoStuff();
 Task.WaitAll(task, lookupTask);
person MBen    schedule 10.01.2013