TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.76K subscribers
Post #1402 1.69K
День 1136. #ЗаметкиНаПолях #AsyncTips
Модульное тестирование async-методов

Задача:
Имеется async-метод, для которого необходимо провести модульное тестирование.

Решение
Многие современные фреймворки модульного тестирования, включая MSTest, NUnit и xUnit, поддерживают методы модульного тестирования async Task. Пример асинхронного модульного теста в MSTest:
[TestMethod]
public async Task MethodAsync_False()
{
var sut = …;
var result = await sut.MethodAsync();
Assert.IsFalse(result);
}

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

Если ваш фреймворк модульного тестирования не поддерживает модульные тесты с async Task, то ему придётся помочь с ожиданием тестируемой асинхронной операции. Один из вариантов — использовать GetAwaiter().GetResult() для синхронного блокирования по задаче. Использование GetAwaiter().GetResult() вместо Wait() позволит избежать обёртки в AggregateException, когда в задаче произойдёт исключение.

Имитация (mocking) асинхронных зависимостей на первый взгляд кажется немного неуклюжей. Всегда желательно хотя бы проверить, как ваши методы реагируют на синхронный успех (имитация с Task.FromResult), синхронные ошибки (имитация с Task.FromException) и асинхронный успех (имитация с Task.Yield и возвратом значения). Task.FromResult и Task.FromException рассматривались здесь. Task.Yield может использоваться для принудительного применения асинхронного поведения и задействуется прежде всего при модульном тестировании:
interface IMyInterface
{
Task<int> SomeAsync();
}
class SyncSuccess : IMyInterface
{
public Task<int> SomeAsync()
{
return Task.FromResult(42);
}
}

class SyncError : IMyInterface
{
public Task<int> SomeAsync()
{
return Task.FromException<int>(
new InvalidOperationException());
}
}

class AsyncSuccess : IMyInterface
{
public async Task<int> SomeAsync()
{
// Принудительно включаем асинхронное поведение
await Task.Yield();
return 42;
}
}

При тестировании асинхронного кода взаимоблокировки и состояния гонки могут проявляться чаще, чем при тестировании синхронного кода. Может быть полезным назначение тайм-аута тестам. Тестовому методу можно задать атрибут Timeout(int timeOut), передав ему количество миллисекунд таймаута. Значение по умолчанию - TestTimeout.Infinite ("бесконечно").

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 7.
  • 👍 8
More from @netdeveloperdiary
  1. Oct 15, 2026Post #3374
  2. Oct 14, 2026Post #3373
  3. Oct 13, 2026День 2813. #ЗаметкиНаПолях #Async Ещё Раз Про Async/Await в C#. Часть 1 Почему существует…
  4. Oct 12, 2026День 2812. #Карьера #AI Как Разработчикам Оставаться Полезными, Когда Код Пишет ИИ? По мер…
  5. Oct 11, 2026День 2811. #ВопросыНаСобеседовании Марк Прайс предложил свой набор из 60 вопросов (как тех…
  6. Oct 10, 2026День 2810. #ЧтоНовенького #VSCode Более Быстрый и Лёгкий C# Dev Kit Мы, разработчики, люби…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →