BLoC Testing with Mockito in Flutter


When working with Flutter and BLoC for state management, it’s crucial to write robust tests to ensure your app behaves correctly. In this blog, we’ll walk through testing a Flutter BLoC using Mockito, focusing on a repository pattern.
Steps Covered:
Define an abstract repository (
ChallanRepo
)Implement the repository (
ChallanRepoImpl
)Create a BLoC (
ChallanBloc
) to fetch a list of challansWrite unit tests using Mockito for the BLoC’s behavior
1️⃣ Define the Abstract Repository
We start by creating an abstract class ChallanRepo
, which declares the getChallanList()
method.
abstract class ChallanRepo {
Future<List<String>> getChallanList();
}
2️⃣ Implement the Repository (ChallanRepoImpl
)
This class simulates an API call by returning a hardcoded list after a delay.
class ChallanRepoImpl implements ChallanRepo {
@override
Future<List<String>> getChallanList() async {
await Future.delayed(Duration(seconds: 1));
return ["Challan 101", "Challan 102", "Challan 103"];
}
}
3️⃣ Create the BLoC (ChallanBloc
)
The BLoC manages states and events related to fetching challan data.
📌 Events
abstract class ChallanEvent {}
class GetChallanEvent extends ChallanEvent {}
📌 States
abstract class ChallanState {}
class ChallanListLoadingState extends ChallanState {}
class ChallanListEmptyState extends ChallanState {}
class ChallanListLoadedState extends ChallanState {
final List<String> challanList;
ChallanListLoadedState(this.challanList);
}
class ChallanListErrorState extends ChallanState {
final String message;
ChallanListErrorState(this.message);
}
📌 BLoC Implementation
import 'package:flutter_bloc/flutter_bloc.dart';
class ChallanBloc extends Bloc<ChallanEvent, ChallanState> {
final ChallanRepo challanRepo;
ChallanBloc(this.challanRepo) : super(ChallanListLoadingState()) {
on<GetChallanEvent>(_onGetChallanList);
}
Future<void> _onGetChallanList(
GetChallanEvent event, Emitter<ChallanState> emit) async {
try {
emit(ChallanListLoadingState());
final challanList = await challanRepo.getChallanList();
if (challanList.isEmpty) {
emit(ChallanListEmptyState());
} else {
emit(ChallanListLoadedState(challanList));
}
} catch (e) {
emit(ChallanListErrorState("Failed to fetch challans"));
}
}
}
4️⃣ Writing Tests with Mockito
📌 Install Dependencies
Add the necessary dependencies to pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
flutter_bloc: <take latest version>
mockito: <take latest version>
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: <take latest version>
build_runner: <take latest version>
bloc_test: <take latest version>
Run:
flutter pub get
📌 Step 2: Generate Mock Class
Create a test file: test/challan_bloc_test.dart
and add:
import 'package:mockito/annotations.dart';
import '../lib/challan_repo.dart';
@GenerateMocks([ChallanRepo])
void main() {}
Generate the mock class by running:
flutter pub run build_runner build
This creates test/challan_bloc_test.mocks.dart
.
📌 Step 3: Write the Test
Create test/challan_bloc_test.dart
and add the following:
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:mockito/annotations.dart';
import 'package:bloc_test/bloc_test.dart';
import '../lib/challan_repo.dart';
import '../lib/challan_bloc.dart';
import 'challan_bloc_test.mocks.dart';
@GenerateMocks([ChallanRepo])
void main() {
late ChallanBloc challanBloc;
late MockChallanRepo mockChallanRepo;
setUp(() {
mockChallanRepo = MockChallanRepo();
challanBloc = ChallanBloc(mockChallanRepo);
});
tearDown(() {
challanBloc.close();
});
test("Initial state should be ChallanListLoadingState", () {
expect(challanBloc.state, isA<ChallanListLoadingState>());
});
blocTest<ChallanBloc, ChallanState>(
"Should emit [ChallanListLoadingState, ChallanListLoadedState] when fetching challans successfully",
build: () {
when(mockChallanRepo.getChallanList()).thenAnswer(
(_) async => ["Challan 101", "Challan 102", "Challan 103"]);
return challanBloc;
},
act: (bloc) => bloc.add(GetChallanEvent()),
expect: () => [
ChallanListLoadingState(),
ChallanListLoadedState(["Challan 101", "Challan 102", "Challan 103"]),
],
);
blocTest<ChallanBloc, ChallanState>(
"Should emit [ChallanListLoadingState, ChallanListEmptyState] when API returns an empty list",
build: () {
when(mockChallanRepo.getChallanList()).thenAnswer((_) async => []);
return challanBloc;
},
act: (bloc) => bloc.add(GetChallanEvent()),
expect: () => [ChallanListLoadingState(), ChallanListEmptyState()],
);
blocTest<ChallanBloc, ChallanState>(
"Should emit [ChallanListLoadingState, ChallanListErrorState] when API throws an error",
build: () {
when(mockChallanRepo.getChallanList()).thenThrow(Exception("API error"));
return challanBloc;
},
act: (bloc) => bloc.add(GetChallanEvent()),
expect: () => [ChallanListLoadingState(), ChallanListErrorState("Failed to fetch challans")],
);
}
🔥 Recap
✔ Created ChallanRepo
(abstract class) and ChallanRepoImpl
(implementation).
✔ Implemented ChallanBloc
with GetChallanEvent
and state management.
✔ Used Mockito to test the BLoC’s behavior.
✔ Tested success, empty, and error cases using bloc_test
.
By following this structured approach, you can ensure your Flutter BLoC is well-tested and functions correctly in different scenarios. Happy coding! 🚀
Subscribe to my newsletter
Read articles from NonStop io Technologies directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

NonStop io Technologies
NonStop io Technologies
Product Development as an Expertise Since 2015 Founded in August 2015, we are a USA-based Bespoke Engineering Studio providing Product Development as an Expertise. With 80+ satisfied clients worldwide, we serve startups and enterprises across San Francisco, Seattle, New York, London, Pune, Bangalore, Tokyo and other prominent technology hubs.