Розробка Widget-тестів для Flutter-додатку

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

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

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

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

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Розробка Widget-тестів для Flutter-додатку
Середній
~3-5 днів
Часті запитання

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

Етапи розробки

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

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Розробка Widget-тестів для Flutter-додатків

Widget-тести у Flutter займають нішу, яку зазвичай заповнюють або unit-тести (занадто дрібні), або інтеграційні тести (занадто повільні) у мобільній розробці. Рендеринг віджетів, навігація за дотиком кнопки, відображення даних з провайдера — все це перевіряється без запуску на фізичному пристрої, за секунди, через WidgetTester та синтетичний рушій рендерингу.

Поширені початкові проблеми

Найчастіша помилка: спроба написати widget-тест для віджета, який залежить від реального BuildContext — наприклад, такий, що читає Theme.of(context) і падає з No MaterialApp found або No Directionality widget. Рішення — завжди обертати тестований віджет у MaterialApp або мінімальний Directionality:

await tester.pumpWidget(
  MaterialApp(home: MyWidget()),
);

Друга проблема — RenderFlex overflowed у тестах, яких не було в дебагері. Це означає, що розмір WidgetTester за замовчуванням (800×600) не збігається з реальним пристроєм. Виправте це через tester.binding.window.physicalSizeTestValue або tester.view.physicalSize = const Size(390, 844) (у поточному Flutter 3.x API).

Архітектура Widget-тестів

Структура тест-файлу відображає структуру віджета: test/widgets/ дзеркалює lib/widgets/. Кожен тест-файл відповідає одному віджету або одному екрану.

group('LoginScreen', () {
  testWidgets('shows error when email is invalid', (tester) async {
    await tester.pumpWidget(MaterialApp(home: LoginScreen()));

    await tester.enterText(find.byKey(Key('email_field')), 'not-an-email');
    await tester.tap(find.byKey(Key('submit_button')));
    await tester.pump(); // синхронний кадр

    expect(find.text('Введіть коректну електронну пошту'), findsOneWidget);
  });
});

pump() vs pumpAndSettle() — критичне розрізнення. pump() малює один кадр. pumpAndSettle() циклює кадри, поки не залишиться жодних очікуючих анімацій. На віджетах з нескінченними анімаціями (AnimatedBuilder з repeat: true) pumpAndSettle() зависне навічно — використовуйте pump(Duration(seconds: 2)).

Мокування провайдерів та залежностей

Widget-тест без мокування залежностей — це не widget-тест, це інтеграційний тест. Для Riverpod переопишіть провайдери через ProviderScope.overrides:

await tester.pumpWidget(
  ProviderScope(
    overrides: [
      userProvider.overrideWithValue(AsyncValue.data(mockUser)),
    ],
    child: MaterialApp(home: ProfileScreen()),
  ),
);

Для BLoCBlocProvider з мок-блоком через mocktail або mockito. Для GetIt — зареєструйте мок-реалізацію перед тестом і скиньте після через tearDown.

Golden Tests

Golden Tests — окремена категорія. Віджет рендериться, скриншот порівнюється з еталонним .png у test/goldens/. При першому запуску еталон генерується (flutter test --update-goldens), при наступних — будь-яке пікельне розходження ламає тест.

testWidgets('PrimaryButton golden', (tester) async {
  await tester.pumpWidget(
    MaterialApp(
      home: Center(child: PrimaryButton(label: 'Зберегти')),
    ),
  );
  await expectLater(
    find.byType(PrimaryButton),
    matchesGoldenFile('goldens/primary_button.png'),
  );
});

Проблема з Golden Tests: вони залежать від платформи. Шрифти, згладжування, рендеринг тіней — усе відрізняється на macOS, Linux та Windows CI. Рішення — запускайте golden-тести тільки на певній платформі (canvaskit рушій у CI через flutter test --platform chrome для web, або фіксований Ubuntu Docker-образ для мобільних golden'ів).

Пакет golden_toolkit (pub.dev) додає loadAppFonts(), що усуває прямокутники замість тексту в еталонах.

Async та Future у тестах

Якщо віджет запускає Future при ініціалізації (наприклад, FutureBuilder + HTTP-запит), тест повинен контролювати завершення цього future. Без мокування мережевий виклик либо падає, либо зависає.

when(() => mockApiService.getUser()).thenAnswer((_) async => mockUser);

await tester.pumpWidget(/* ... */);
await tester.pump(); // запускає FutureBuilder
await tester.pump(Duration.zero); // чекаємо завершення Future

Fake замість Mock — коли поведінка складна. Реалізуйте FakeAuthService extends AuthService, переопишіть необхідні методи — чище, ніж stub кожного виклику.

Що включено

  • Написання widget-тестів для всіх ключових екранів та компонентів
  • Налаштування Golden Tests з коректною платформою для CI
  • Мокування провайдерів (Riverpod, BLoC, Provider, GetIt)
  • Охоплення edge-케йсів: порожні стани, помилки, завантаження
  • Налаштування запуску у CI з звітом про покриття

Строки

3–5 днів для проекту зі стандартним набором екранів (10–20 віджетів). Golden Tests для всієї бібліотеки UI-компонентів — окремо розрахунок. Вартість розраховується індивідуально.