В моем коде у меня есть метод, такой как:
void PerformWork(List<Item> items)
{
HostingEnvironment.QueueBackgroundWorkItem(async cancellationToken =>
{
foreach (var item in items)
{
await itemHandler.PerformIndividualWork(item);
}
});
}
Где Item
- это просто известная модель, а itemHandler
просто выполняет некоторую работу на основе модели (класс ItemHandler
). определяется в отдельной поддерживаемой кодовой базе как nuget pkg, я бы не хотел его изменять). Цель этого кода - выполнить работу для списка элементов в фоновом режиме, но синхронно.
В рамках этой работы я хотел бы создать модульный тест для проверки того, что при вызове этого метода элементы обрабатываются синхронно. Я почти уверен, что проблему можно упростить до следующего:
await MyTask(1);
await MyTask(2);
Assert.IsTrue(/* MyTask with arg 1 was completed before MyTask with arg 2 */);
Первая часть этого кода, которую я могу легко протестировать, состоит в том, что последовательность поддерживается. Например, используя NSubstitute, я могу проверить порядок вызовов методов в коде библиотеки:
Received.InOrder(() =>
{
itemHandler.PerformIndividualWork(Arg.Is<Item>(arg => arg.Name == "First item"));
itemHandler.PerformIndividualWork(Arg.Is<Item>(arg => arg.Name == "Second item"));
itemHandler.PerformIndividualWork(Arg.Is<Item>(arg => arg.Name == "Third item"));
});
Но я не совсем уверен, как убедиться, что они не работают параллельно. У меня было несколько идей, которые кажутся плохими, например, насмешка над библиотекой с искусственной задержкой при вызове PerformIndividualWork
, а затем либо проверка времени, прошедшего для всей фоновой задачи, находящейся в очереди, либо проверка временных отметок itemHandler
полученных вызовов для минимальное время между звонками. Например, если у меня PerformIndividualWork
смоделировано, чтобы задержать 500 миллисекунд, и я ожидаю три элемента, то я могу проверить истекшее время:
stopwatch.Start();
// I have an interface instead of directly calling HostingEnvironment, so I can access the task being queued here
backgroundTask.Invoke(...);
stopwatch.Stop();
Assert.IsTrue(stopwatch.ElapsedMilliseconds > 1500);
Но это не так и может привести к ложному позитивы. Возможно, решение заключается в модификации самого кода; тем не менее, я не могу придумать, как осмысленно изменить его, чтобы сделать возможным такого рода модульное тестирование (задачи тестирования выполняются по порядку). Мы обязательно проведем системное / интеграционное тестирование, чтобы гарантировать, что проблема, вызванная асинхронной производительностью отдельных элементов, не возникнет, но я бы хотел провести тестирование здесь и на этом уровне.