Как создать макет списка асинхронных задач для модульного тестирования функции

#c# #unit-testing #async-await #task #moq

#c# #модульное тестирование #async-await #задача #moq

Вопрос:

У меня есть функция, которая принимает список Task<T> и возвращает int значение, указывающее, сколько из этих задач выполняется в данный момент времени.

  public int GetActiveTasks(List<Task<SomeClass>> tasks)
        {
            return tasks.Count(x=>
                x.Status == TaskStatus.Created ||
                x.Status == TaskStatus.Running ||
                x.Status == TaskStatus.WaitingForActivation ||
                x.Status == TaskStatus.WaitingToRun ||
                x.Status == TaskStatus.WaitingForChildrenToComplete);
        }
  

Теперь проблема в том, что я хочу написать несколько модульных тестов вокруг этого, но свойство Status в задаче не имеет установщика (что имеет смысл — с чего бы это?)

Итак, мой план состоял в том, чтобы создать список таких задач :

 var taskList = new List<Task<SomeClass>>()
            {
                new Task<SomeClass>() { Status = TaskStatus.Running },
                new Task<SomeClass>() { Status = TaskStatus.Cancelled },
            };
  

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

Но поскольку я не могу явно установить статус, я немного застрял.

Есть идеи?

Комментарии:

1. Task.FromResults , Task.FromException , Task.FromCancelled , Task.Delay() и зачем вам нужно проверять Waiting статусы?

2. Task.WhenAll вероятно, возвращает задачу, ожидающую завершения дочерних элементов

3. Это долгая история, но у нас есть бизнес-требование отправлять кучу данных в сторонний API, но он не может обрабатывать более x запросов одновременно (скажем, 5). Итак, нам нужно отправить 100 запросов партиями по 5. Мы можем либо отправить 5, либо использовать whenall() перед отправкой большего количества, что неэффективно, поскольку для завершения некоторых может потребоваться 20 мс, а для некоторых может потребоваться 20000 мс… поэтому вместо этого мы отслеживаем, сколько у нас задач и каков их статус, мы отправляем 5 запросов в API, и по мере возвращения каждой задачи мы отправляем еще один запрос, поэтому, пока у нас есть работа в очереди, у нас всегда будет 5 незавершенных задач.

4. Тогда вам не нужно проверять статусы задач, вам нужно, например ActionBlock<T> , с MaxDegreeOfParallelism установленным значением 5. Например var block=new ActionBlock<T>(t=>someAction(t),new ExecutionDataFlowBlockOptions{MaxDegreeOfParallelism=5}); foreach(var msg in messages){ block.Post(msg);} block.Complete(); await block.Completion;

5. ДА. По умолчанию используется по одному. Параллелизм возникает при выполнении каждого блока в конвейере в его собственном потоке. Ничто не мешает вам увеличить DOP до того, что вы хотите