Разработка Unit-тестов для Flutter-приложения

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

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

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Разработка Unit-тестов для Flutter-приложения
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Разработка Unit-тестов для Flutter-приложения

Flutter поставляется с flutter_test из коробки, но написать хорошие тесты — не то же самое, что просто написать тесты. Типичная проблема Flutter-проектов: тесты есть, но они тестируют только «sunny day scenario», падают при малейшем изменении структуры, или держат внутри себя реальные HTTP-запросы.

Стек для unit-тестов

  • flutter_test — встроенный, основной
  • mocktail — предпочтительнее mockito для Dart: не требует кодогенерации
  • bloc_test — для BLoC/Cubit
  • riverpod + ProviderContainer — для Riverpod-based логики
  • fake_async — тестирование кода с Future.delayed и Timer

Тестирование BLoC

BLoC — самая тестируемая архитектура в Flutter. bloc_test делает assert последовательности состояний тривиальным:

blocTest<AuthCubit, AuthState>(
  'emits [loading, authenticated] when login succeeds',
  build: () {
    when(() => mockAuthRepo.login(any(), any()))
        .thenAnswer((_) async => User(id: '1', name: 'Test'));
    return AuthCubit(authRepository: mockAuthRepo);
  },
  act: (cubit) => cubit.login('[email protected]', 'password'),
  expect: () => [
    const AuthState.loading(),
    AuthState.authenticated(User(id: '1', name: 'Test')),
  ],
);

Если в act нужна задержка или асинхронность — await cubit.login(...) внутри act.

Тестирование Riverpod

ProviderContainer позволяет создать изолированное окружение с переопределёнными провайдерами:

test('userProvider returns user on success', () async {
  final container = ProviderContainer(
    overrides: [
      userRepositoryProvider.overrideWithValue(MockUserRepository()),
    ],
  );
  addTearDown(container.dispose);

  when(() => mockRepo.getUser('1')).thenAnswer((_) async => User(id: '1'));

  final user = await container.read(userProvider('1').future);
  expect(user.id, '1');
});

Тестирование Use Case и Repository

Use Case — чистая бизнес-логика без Flutter-зависимостей. Тестируется просто:

test('GetOrderUseCase applies discount when user is premium', () async {
  when(() => mockOrderRepo.getOrder('order1'))
      .thenAnswer((_) async => Order(price: 100, isPremium: true));

  final result = await useCase.execute('order1');

  expect(result.finalPrice, 85);  // 15% скидка
});

Частая ошибка: тестировать Use Case через ViewModel/BLoC, а не напрямую. Это делает тест хрупким и медленным.

fake_async для кода с таймерами

test('debounce search fires after 300ms', () {
  fakeAsync((async) {
    final controller = SearchController();
    controller.query = 'flutter';

    async.elapse(Duration(milliseconds: 200));
    verifyNever(() => mockRepo.search(any()));

    async.elapse(Duration(milliseconds: 100));
    verify(() => mockRepo.search('flutter')).called(1);
  });
});

fakeAsync позволяет управлять временем без реального sleep — тесты с debounce/throttle запускаются мгновенно.

Типичные ошибки

  • mocktail без registerFallbackValue для кастомных типов — any() не работает с нестандартными классами без регистрации
  • Тесты, которые мутируют глобальный stateSharedPreferences или Hive в тестах нужно инициализировать через SharedPreferences.setMockInitialValues({}) перед каждым тестом
  • Отсутствие tearDownProviderContainer.dispose() и StreamController.close() забывают, и тесты текут памятью

CI-интеграция

flutter test --coveragelcov.infogenhtml для HTML-отчёта. В GitHub Actions добавляем шаг с flutter analyze + flutter test на каждый PR. Для фильтрации покрытия (исключаем generated-файлы) — remove_from_coverage пакет или sed-фильтр по lcov.info.

Срок: 3–5 дней в зависимости от объёма проекта и используемой архитектуры (BLoC / Riverpod / GetX).