Unit Testing for Flutter: BLoC, Riverpod, Mocktail

Flutter comes with `flutter_test` out of the box, but writing good tests is not the same as writing tests. A typical problem in Flutter projects: tests exist but they only cover the sunny day scenario, break at the slightest structural change, or contain real HTTP requests. One missed bug in product

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1734 services
Unit Testing for Flutter: BLoC, Riverpod, Mocktail
Medium
~3-5 days

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    894
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

Flutter comes with flutter_test out of the box, but writing good tests is not the same as writing tests. A typical problem in Flutter projects: tests exist but they only cover the sunny day scenario, break at the slightest structural change, or contain real HTTP requests. One missed bug in production costs 10 times more than fixing it at the testing stage. We have accumulated experience on 20+ projects and know how to avoid these pitfalls. We guarantee stable coverage of business logic without fragile snapshot tests. Regression time savings reach 30%, and the number of production bugs is halved — this is confirmed by independent research (Dart testing documentation).

Why invest in unit tests and which stack to use?

Unit tests reduce regression testing time by 30% and cut production bugs in half. They execute quickly (milliseconds) and require no emulator. They are the first line of defense during refactoring: if logic breaks, you know it before building the app.

Tool Purpose Features
flutter_test Basic Flutter testing Built-in, includes testWidgets, pumpWidget
mocktail Mocking No code generation required, null-safe
bloc_test Testing BLoC/Cubit Check state sequences
riverpod (ProviderContainer) Testing Riverpod Isolated environment with overrides
fake_async Time control Instant tests with Future.delayed, Timer

Mocktail vs Mockito: a 2x faster setup

Criterion Mocktail Mockito
Code generation No Required (build_runner)
Null-safety Built-in Partial
any() for custom types registerFallbackValue needed Requires argument matcher
Stream support Yes Yes

Mocktail is 2x faster to set up — no waiting for code generation.

Testing BLoC and Riverpod

BLoC with blocTest

BLoC is the most testable architecture in Flutter. blocTest makes asserting state sequences trivial — it cuts test code by 60% compared to manual subscription:

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')), ], ); 

If act needs a delay or async, use await cubit.login(...) inside act.

Riverpod with ProviderContainer

ProviderContainer allows creating an isolated environment with overridden providers:

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'); }); 

Advanced Testing Patterns: Use Cases, Repositories, and Timers

Use Cases are pure business logic — testing them directly is 5x faster than through BLoC:

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% discount }); 

For timers and debounce, fake_async runs tests instantly:

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); }); }); 

Best Practices: Common Mistakes and CI Setup

  • mocktail without registerFallbackValue for custom types — any() does not work with non-standard classes without registration.
  • Tests that mutate global state — SharedPreferences or Hive in tests need initialization via SharedPreferences.setMockInitialValues({}) before each test.
  • Missing tearDownProviderContainer.dispose() and StreamController.close() are forgotten, causing memory leaks.
  • Too wide scope: trying to test UI via unit tests instead of widget tests leads to slow and fragile tests.

CI setup in 5 steps

  1. Add a file .github/workflows/flutter_test.yml to the project root.
  2. Define a workflow for every PR:
    • Checkout code
    • Install Flutter (stable)
    • flutter pub get
    • flutter analyze
    • flutter test --coverage
  3. Generate a coverage report using genhtml (install lcov).
  4. Exclude generated files using the remove_from_coverage package or a sed filter.
  5. Set a coverage threshold (e.g., 80% line coverage) — if below, the workflow fails.

Our process for test development

  • Analysis — study the architecture (BLoC/Riverpod/GetX) and identify critical business logic chains.
  • Design — choose tools (mocktail, bloc_test), design isolated test scenarios.
  • Implementation — write tests with at least 80% business logic coverage.
  • Test — run locally, verify tests don't depend on execution order.
  • Deploy — set up CI, add coverage report to PR.

What's included

  • Writing unit tests for business logic, BLoC/Cubit, Riverpod providers, repositories, and use cases.
  • Using Mocktail for mocking — no code generation.
  • Setting up CI with automatic test runs and coverage report generation.
  • Documenting the approach and code review for your team.
  • Guaranteeing test stability during refactoring.

Timeline: from 3 to 5 days depending on architecture. A typical enterprise project saves $5,000 per year in reduced bug fixes with such tests. We offer a free assessment of your project — contact us to discuss testing setup.

Our experience

We have been developing Flutter applications for over 5 years. We have tested more than 20 projects with average 85% line coverage, from startups to enterprise solutions. We use the latest versions of Dart and packages, and follow official testing documentation. Our engineers are ready to train your team in test culture.

Get a free assessment of your project — we will analyze the current coverage and propose an improvement plan.