Розробка юніт-тестів для Flutter: BLoC, Riverpod, Mocktail

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

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Розробка юніт-тестів для Flutter: BLoC, Riverpod, Mocktail
Середній
~3-5 днів

Наші компетенції:

Часті запитання

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    597

Flutter поставляється з flutter_test з коробки, але написати хороші тести — не те саме, що просто написати тести. Типова проблема Flutter-проєктів: тести є, але вони тестують лише «sunny day scenario», падають при найменшій зміні структури, або містять у собі реальні HTTP-запити. Один пропущений баг у production обходиться в 10 разів дорожче, ніж виправлення на етапі тестування. Ми накопичили досвід на 20+ проєктах і знаємо, як уникнути цих граблів. Гарантуємо стабільне покриття бізнес-логіки без крихких snapshot-тестів. Економія часу на регресії досягає 30%, а кількість багів у продакшні скорочується вдвічі — це підтверджують незалежні дослідження (Dart testing documentation).

Чому варто інвестувати в юніт-тести для Flutter?

Юніт-тести скорочують час регресійного тестування на 30% і знижують кількість багів у продакшні вдвічі. Вони швидко виконуються (мілісекунди) і не потребують емулятора. Це перша лінія оборони при рефакторингу: якщо логіка зламалася, ви дізнаєтеся про це до збірки застосунку.

Стек для юніт-тестів

Інструмент Призначення Особливості
flutter_test Базовий набір для Flutter Вбудований, містить testWidgets, pumpWidget
mocktail Створення моків Не потребує кодогенерації, нуль-безпечний
bloc_test Тестування BLoC/Cubit Перевірка послідовності станів
riverpod (ProviderContainer) Тестування Riverpod Ізольоване середовище з перевизначеннями
fake_async Контроль часу Миттєві тести з Future.delayed, Timer

Порівняння Mocktail та Mockito

Критерій Mocktail Mockito
Кодогенерація Ні Потрібна (build_runner)
Null-safety З коробки Частково
any() для кастомних типів Потрібна registerFallbackValue Потрібен аргумент matcher
Підтримка Stream Є Є

Mocktail у 2 рази швидше налаштовується — не потрібно чекати кодогенерації.

Як тестувати BLoC за допомогою blocTest?

BLoC — найбільш тестована архітектура у Flutter. blocTest робить перевірку послідовності станів тривіальною:

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. blocTest у 3 рази скорочує код порівняно з ручним підписуванням на стейт.

Як тестувати 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 запускаються миттєво.

Типові помилки при юніт-тестуванні Flutter

  • mocktail без registerFallbackValue для кастомних типів — any() не працює з нестандартними класами без реєстрації.
  • Тести, які мутують глобальний state — SharedPreferences або Hive у тестах потрібно ініціалізувати через SharedPreferences.setMockInitialValues({}) перед кожним тестом.
  • Відсутність tearDownProviderContainer.dispose() та StreamController.close() забувають, і тести течуть пам'яттю.
  • Занадто широкий охват: намагаються тестувати UI через юніт-тести замість widget-тестів — це призводить до повільних і крихких тестів.

Як налаштувати CI для автоматичного прогону тестів? Покрокова інструкція

  1. Додайте в корінь проєкту файл .github/workflows/flutter_test.yml.
  2. Визначте workflow на кожен PR:
    • Checkout коду
    • Встановлення Flutter (stable)
    • flutter pub get
    • flutter analyze
    • flutter test --coverage
  3. Для формування звіту про покриття використовуйте genhtml (встановіть lcov).
  4. Виключіть generated-файли за допомогою пакета remove_from_coverage або sed-фільтра.
  5. Налаштуйте поріг покриття (наприклад, 80% рядків коду) — при падінні нижче workflow завершиться помилкою.

Процес роботи над тестами

  • Аналіз — вивчаємо архітектуру (BLoC/Riverpod/GetX) і визначаємо критичні бізнес-логічні ланцюжки.
  • Проєктування — обираємо інструменти (mocktail, bloc_test), проєктуємо ізольовані тестові сценарії.
  • Реалізація — пишемо тести з покриттям не менше 80% бізнес-логіки.
  • Тест — проганяємо локально, перевіряємо, що тести не залежать від порядку виконання.
  • Деплой — налаштовуємо CI, додаємо звіт про покриття в PR.

Що входить у роботу

  • Написання юніт-тестів для бізнес-логіки, BLoC/Cubit, Riverpod-провайдерів, репозиторіїв та use case.
  • Використання Mocktail для моків — без кодогенерації.
  • Налаштування CI з автоматичним прогоном тестів та формуванням звіту про покриття.
  • Документування підходу та код-рев'ю вашої команди.
  • Гарантія стабільності тестів при рефакторингу.

Строки: від 3 до 5 днів залежно від архітектури (BLoC / Riverpod / GetX). Оцінимо ваш проєкт безкоштовно — зв'яжіться з нами для отримання консультації з налаштування тестування.

Наш досвід

Ми займаємося розробкою Flutter-застосунків більше 5 років. За цей час протестували понад 20 проєктів: від стартапів до enterprise-рішень. Використовуємо актуальні версії Dart та пакетів, стежимо за офіційною документацією з тестування. Наші інженери готові навчити вашу команду культурі написання тестів.

Замовте безкоштовну оцінку вашого проєкту — ми проаналізуємо поточне покриття та запропонуємо план покращень.