Если вы пишете тесты во Flutter, то наверняка сталкивались с тем, как сложно тестировать асинхронные операции. Часто такие операции приходится мокать или обходить с помощью Future.delayed. Но что делать, если в коде используются не только отложенные Future, но и настоящие таймеры, задержки и другие механизмы, зависящие от времени?
Сегодня поговорим о пакете fake_async, который может помочь с этим делом.
Пакет fake_async создан для тестирования кода, зависящего от времени. Flutter-тесты могут запускаться в специальной зоне FakeAsync, где вы управляете временем вручную. То есть fake_async перехватывает все стандартные Dart-таймеры и заменяет их на свои «поддельные». Благодаря этому вы можете контролировать время в тестах, не дожидаясь реальных секунд или минут.
Например, у вас есть функция, которая загружает данные с задержкой:
Future<String> fetchData() {
return Future.delayed(Duration(seconds: 2), () => 'Data loaded');
}
Без fake_async тестирование этой функции потребовало бы реальной 2-секундной задержки.
Попробуем заменить на fake_async.
import 'package:fake_async/fake_async.dart';
import 'package:test/test.dart';
void main() {
test('fetchData должен вернуть "Data loaded" через 2 секунды', () {
fakeAsync((async) { // 1. Оборачиваем тест в fakeAsync()
final future = fetchData();
async.elapse(Duration(seconds: 2)); // 2. Перемещаем виртуальное время на 2 секунды
expect(future, completion('Data loaded')); // 3. Немедленно проверяем результат
});
});
}
fakeAsync() создает виртуальное время, которым можно управлять вручную через elapse(). Это позволяет имитировать прохождение времени и тут же проверять результат асинхронных операций — без реальных пауз.
Также у fake_async есть другие полезные методы:
▪️ flushTimers() — для мгновенного выполнения всех запланированных таймеров
▪️ advanceTime(Duration duration) — похож на elapse, но иногда дает чуть более тонкий контроль
Хотя fake_async очень полезен, у него есть свои особенности, которые важно учитывать:
✅ каждый вызов fakeAsync(...) создает свою виртуальную временную зону, полностью изолированную от других
✅ он не управляет async/await напрямую, только таймерами и микрозадачами
✅ может конфликтовать с
tester.runAsync в flutter_test✅
elapse() не влияет на scheduleMicrotask — только на макрозадачи✅ потоки типа
Stream.periodic могут вести себя нестабильно✅ в
flutter_test возможны конфликты с фреймами и анимациями❤️ — если было полезно
