Unit Testing Bloc Cubits with Mockito in Flutter

Summary
Summary
Summary
Summary

This tutorial guides you through setting up Mockito in Flutter app tests, creating a Cubit and repository, and mocking external dependencies to verify state transitions. It demonstrates writing unit tests using expectLater and bloc_test to assert emissions for success, failure, and exception cases. Integrating this workflow into CI pipelines boosts test speed, reliability, and confidence in business logic.

This tutorial guides you through setting up Mockito in Flutter app tests, creating a Cubit and repository, and mocking external dependencies to verify state transitions. It demonstrates writing unit tests using expectLater and bloc_test to assert emissions for success, failure, and exception cases. Integrating this workflow into CI pipelines boosts test speed, reliability, and confidence in business logic.

This tutorial guides you through setting up Mockito in Flutter app tests, creating a Cubit and repository, and mocking external dependencies to verify state transitions. It demonstrates writing unit tests using expectLater and bloc_test to assert emissions for success, failure, and exception cases. Integrating this workflow into CI pipelines boosts test speed, reliability, and confidence in business logic.

This tutorial guides you through setting up Mockito in Flutter app tests, creating a Cubit and repository, and mocking external dependencies to verify state transitions. It demonstrates writing unit tests using expectLater and bloc_test to assert emissions for success, failure, and exception cases. Integrating this workflow into CI pipelines boosts test speed, reliability, and confidence in business logic.

Key insights:
Key insights:
Key insights:
Key insights:
  • Mockito setup: Add dev dependencies, annotate dependencies, and generate mocks for controlled testing.

  • Cubit design: Isolate business logic by calling repository.fetchNextCount in increment(), enabling pure state testing.

  • Mock success/failure: Simulate repository responses to test state emissions for multiple increment scenarios.

  • bloc_test utility: Use build, act, expect, and errors parameters for clear, declarative unit tests.

  • Exception handling: Mock repository exceptions to verify Cubit surfaces errors correctly.

Introduction

Unit testing is a critical part of building robust Flutter applications, especially when you’re using Bloc Cubits for state management. By isolating your business logic in Cubits and mocking external dependencies with Mockito, you can verify state transitions reliably and quickly. In this tutorial, you’ll learn how to set up Mockito for Flutter bloc testing, create a simple Cubit with a repository, and write unit tests (including bloc_test integration) to cover successful and failure scenarios.

Setting Up Dependencies for Flutter bloc testing

First, add the necessary dev dependencies to your pubspec.yaml:

dev_dependencies:
  flutter_test:
    sdk: flutter
  bloc_test: ^9.0.0
  mockito: ^5.0.0
  build_runner

  1. Run flutter pub get.

  2. Create a file test/mocks.dart and annotate your external dependencies:

    import 'package:mockito/annotations.dart';
    import 'package:your_app/data/counter_repository.dart';
    
    @GenerateMocks([CounterRepository])
    void main() {}
  3. Run flutter pub run build_runner build to generate mocks.mocks.dart.

This setup gives you MockCounterRepository to inject controlled responses in unit tests.

Building a Sample Cubit and Repository

Let’s define a simple repository interface and a Cubit that relies on it. The Cubit will emit a new integer each time increment() is called:

// lib/data/counter_repository.dart
abstract class CounterRepository {
  Future<int> fetchNextCount(int current);
}

// lib/cubit/counter_cubit.dart
import 'package:bloc/bloc.dart';
import '../data/counter_repository.dart';

class CounterCubit extends Cubit<int> {
  final CounterRepository repository;
  CounterCubit(this.repository) : super(0);

  Future<void> increment() async {
    final next = await repository.fetchNextCount(state);
    emit(next);
  }
}

Here, CounterCubit starts at 0 and invokes repository.fetchNextCount(state) in increment(), then emits the new state.

Writing Unit Tests with Mockito

With your mocks generated, you can now write tests that verify state emissions based on mocked repository behavior. Create test/counter_cubit_test.dart:

import 'package:flutter_test/flutter_test.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:mockito/mockito.dart';
import 'package:your_app/cubit/counter_cubit.dart';
import 'package:your_app/data/counter_repository.dart';

import 'mocks.mocks.dart';

void main() {
  late MockCounterRepository mockRepo;

  setUp(() {
    mockRepo = MockCounterRepository();
  });

  test('increment emits [1] when repository returns 1', () async {
    when(mockRepo.fetchNextCount(0))
      .thenAnswer((_) async => 1);

    final cubit = CounterCubit(mockRepo);

    // Asynchronously expect one emission: 1
    expectLater(cubit.stream, emitsInOrder([1]));

    await cubit.increment();
  });

  blocTest<CounterCubit, int>(
    'emits [1, 2] on two increments with bloc_test',
    build: () => CounterCubit(mockRepo),
    act: (cubit) async {
      when(mockRepo.fetchNextCount(0))
        .thenAnswer((_) async => 1);
      when(mockRepo.fetchNextCount(1))
        .thenAnswer((_) async => 2);

      await cubit.increment();
      await cubit.increment();
    },
    expect: () => [1, 2],
  );
}

Explanation:

  • We mock fetchNextCount for specific input states (0 and 1).

  • The first test uses expectLater to observe one state emission.

  • The second leverages bloc_test’s blocTest for a clean, declarative style. It asserts the Cubit emits [1, 2] after two increment() calls.

Leveraging bloc_test for Enhanced Flutter bloc testing

bloc_test provides utilities to:

• Isolate builds with the build callback.

• Sequence multiple actions under act.

• Declaratively assert emissions in expect.

• Handle error states with errors param.

You can further test edge cases by mocking exceptions:

when(mockRepo.fetchNextCount(any))
  .thenThrow(Exception('Network error'));

blocTest<CounterCubit, int>(
  'emits error when repository throws',
  build: () => CounterCubit(mockRepo),
  act: (c) => cubit.increment(),
  errors: () => [isA<Exception>()],
);

This pattern ensures your Bloc Cubit gracefully surfaces exceptions as testable events.

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Unit testing Bloc Cubits with Mockito and bloc_test unlocks faster, more reliable Flutter bloc testing. By mocking your repositories, you decouple network or database logic from Cubit behavior, ensuring pure state-transition tests. Incorporate this workflow into your CI pipeline to catch regressions early and boost confidence in your business logic.

Introduction

Unit testing is a critical part of building robust Flutter applications, especially when you’re using Bloc Cubits for state management. By isolating your business logic in Cubits and mocking external dependencies with Mockito, you can verify state transitions reliably and quickly. In this tutorial, you’ll learn how to set up Mockito for Flutter bloc testing, create a simple Cubit with a repository, and write unit tests (including bloc_test integration) to cover successful and failure scenarios.

Setting Up Dependencies for Flutter bloc testing

First, add the necessary dev dependencies to your pubspec.yaml:

dev_dependencies:
  flutter_test:
    sdk: flutter
  bloc_test: ^9.0.0
  mockito: ^5.0.0
  build_runner

  1. Run flutter pub get.

  2. Create a file test/mocks.dart and annotate your external dependencies:

    import 'package:mockito/annotations.dart';
    import 'package:your_app/data/counter_repository.dart';
    
    @GenerateMocks([CounterRepository])
    void main() {}
  3. Run flutter pub run build_runner build to generate mocks.mocks.dart.

This setup gives you MockCounterRepository to inject controlled responses in unit tests.

Building a Sample Cubit and Repository

Let’s define a simple repository interface and a Cubit that relies on it. The Cubit will emit a new integer each time increment() is called:

// lib/data/counter_repository.dart
abstract class CounterRepository {
  Future<int> fetchNextCount(int current);
}

// lib/cubit/counter_cubit.dart
import 'package:bloc/bloc.dart';
import '../data/counter_repository.dart';

class CounterCubit extends Cubit<int> {
  final CounterRepository repository;
  CounterCubit(this.repository) : super(0);

  Future<void> increment() async {
    final next = await repository.fetchNextCount(state);
    emit(next);
  }
}

Here, CounterCubit starts at 0 and invokes repository.fetchNextCount(state) in increment(), then emits the new state.

Writing Unit Tests with Mockito

With your mocks generated, you can now write tests that verify state emissions based on mocked repository behavior. Create test/counter_cubit_test.dart:

import 'package:flutter_test/flutter_test.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:mockito/mockito.dart';
import 'package:your_app/cubit/counter_cubit.dart';
import 'package:your_app/data/counter_repository.dart';

import 'mocks.mocks.dart';

void main() {
  late MockCounterRepository mockRepo;

  setUp(() {
    mockRepo = MockCounterRepository();
  });

  test('increment emits [1] when repository returns 1', () async {
    when(mockRepo.fetchNextCount(0))
      .thenAnswer((_) async => 1);

    final cubit = CounterCubit(mockRepo);

    // Asynchronously expect one emission: 1
    expectLater(cubit.stream, emitsInOrder([1]));

    await cubit.increment();
  });

  blocTest<CounterCubit, int>(
    'emits [1, 2] on two increments with bloc_test',
    build: () => CounterCubit(mockRepo),
    act: (cubit) async {
      when(mockRepo.fetchNextCount(0))
        .thenAnswer((_) async => 1);
      when(mockRepo.fetchNextCount(1))
        .thenAnswer((_) async => 2);

      await cubit.increment();
      await cubit.increment();
    },
    expect: () => [1, 2],
  );
}

Explanation:

  • We mock fetchNextCount for specific input states (0 and 1).

  • The first test uses expectLater to observe one state emission.

  • The second leverages bloc_test’s blocTest for a clean, declarative style. It asserts the Cubit emits [1, 2] after two increment() calls.

Leveraging bloc_test for Enhanced Flutter bloc testing

bloc_test provides utilities to:

• Isolate builds with the build callback.

• Sequence multiple actions under act.

• Declaratively assert emissions in expect.

• Handle error states with errors param.

You can further test edge cases by mocking exceptions:

when(mockRepo.fetchNextCount(any))
  .thenThrow(Exception('Network error'));

blocTest<CounterCubit, int>(
  'emits error when repository throws',
  build: () => CounterCubit(mockRepo),
  act: (c) => cubit.increment(),
  errors: () => [isA<Exception>()],
);

This pattern ensures your Bloc Cubit gracefully surfaces exceptions as testable events.

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Unit testing Bloc Cubits with Mockito and bloc_test unlocks faster, more reliable Flutter bloc testing. By mocking your repositories, you decouple network or database logic from Cubit behavior, ensuring pure state-transition tests. Incorporate this workflow into your CI pipeline to catch regressions early and boost confidence in your business logic.

Accelerate Flutter Testing & Development

Accelerate Flutter Testing & Development

Accelerate Flutter Testing & Development

Accelerate Flutter Testing & Development

Level up your dev workflow with Vibe Studio’s no-code, AI‑driven Flutter builder. It complements your Mockito and bloc_test setup by generating clean, testable code fast.

Level up your dev workflow with Vibe Studio’s no-code, AI‑driven Flutter builder. It complements your Mockito and bloc_test setup by generating clean, testable code fast.

Level up your dev workflow with Vibe Studio’s no-code, AI‑driven Flutter builder. It complements your Mockito and bloc_test setup by generating clean, testable code fast.

Level up your dev workflow with Vibe Studio’s no-code, AI‑driven Flutter builder. It complements your Mockito and bloc_test setup by generating clean, testable code fast.

Other Insights

Other Insights

Other Insights

Other Insights

Join a growing community of builders today

Join a growing
community

of builders today

Join a growing

community

of builders today

© Steve • All Rights Reserved 2025

© Steve • All Rights Reserved 2025

© Steve • All Rights Reserved 2025

© Steve • All Rights Reserved 2025