bloc_test: blocTest, MockBloc, whenListen
package:bloc_test turns bloc/cubit testing into a declarative form. The main function is blocTest, with these parameters:
- `build` — constructs and returns the bloc under test.
- `setUp` — prepares dependencies before the bloc is created.
- `seed` — seeds an initial state into the bloc (starting from a populated list, say).
- `act` — interacts with the bloc: adds events, calls cubit methods.
- `wait` — a duration to wait for async work such as debounce.
- `skip` — how many emitted states to skip before the assertions (default 0).
- `expect` — the expected sequence of states (a matcher).
- `verify` — extra assertions after
expect(that the repository was called once, for instance). - `errors` — the expected exceptions.
- `tearDown` — cleanup after the test.
Additional tools: `MockBloc`/`MockCubit` for creating a stub bloc, and `whenListen`, which creates a stub response for a bloc's listen method and keeps the state property in sync with the emitted values.
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
late FakeTodoRepository repository;
setUp(() {
repository = FakeTodoRepository();
});
group('TodoBloc', () {
blocTest<TodoBloc, TodoState>(
'TodoStarted → loading, success ardıcıllığı yayımlanır',
build: () => TodoBloc(repository),
act: (bloc) => bloc.add(TodoStarted()),
expect: () => [
const TodoState(status: TodoStatus.loading),
TodoState(status: TodoStatus.success, todos: repository.items),
],
verify: (_) => expect(repository.fetchAllCallCount, 1),
);
blocTest<TodoBloc, TodoState>(
'seed ilə dolu siyahıdan başlayıb element silir',
build: () => TodoBloc(repository),
seed: () => TodoState(
status: TodoStatus.success,
todos: const [Todo(id: '1', title: 'Süd al')],
),
act: (bloc) => bloc.add(TodoDeleted('1')),
expect: () => [
const TodoState(status: TodoStatus.success, todos: []),
],
);
blocTest<TodoBloc, TodoState>(
'iki dəfə göndərilən event droppable ilə bir dəfə işlənir',
build: () => CheckoutBloc(repository) as dynamic,
act: (bloc) => bloc
..add(CheckoutSubmitted(order))
..add(CheckoutSubmitted(order)),
wait: const Duration(milliseconds: 100),
verify: (_) => expect(repository.payCallCount, 1),
);
});
}blocTest: the state sequence plus an extra check with `verify`.
class MockTodoBloc extends MockBloc<TodoEvent, TodoState> implements TodoBloc {}
void main() {
testWidgets('xəta state-ində SnackBar göstərilir', (tester) async {
final bloc = MockTodoBloc();
// whenListen: state ardıcıllığını stub kimi verir və `state`-i sinxronlaşdırır.
whenListen(
bloc,
Stream.fromIterable(const [
TodoState(status: TodoStatus.loading),
TodoState(status: TodoStatus.failure, error: 'Şəbəkə xətası'),
]),
initialState: const TodoState(),
);
await tester.pumpWidget(
MaterialApp(
home: BlocProvider<TodoBloc>.value(
value: bloc,
child: const TodoPage(),
),
),
);
await tester.pump(); // loading
await tester.pump(); // failure → listener işə düşür
expect(find.text('Şəbəkə xətası'), findsOneWidget);
});
}A widget test: isolating the UI with `MockBloc` and `whenListen`.
| What is asserted | Parameter / tool |
|---|---|
| The state sequence (loading → success) | `expect` |
| Starting from a given state | `seed` |
| Debounce/throttle behaviour | `wait` |
| Ignoring the first n states | `skip` |
| That a repository/service was called | `verify` |
| Thrown errors | `errors` |
| Isolating the UI from the bloc entirely | `MockBloc` plus `whenListen` |
Asserting the state sequence with expect is powerful but can be brittle: adding a field to the state class breaks every test. The practical approach is to assert the critical fields with matchers (isA<TodoState>().having((s) => s.status, 'status', TodoStatus.success)) and to require full equality only for small, stable states.
📚 Sources and documentation
- package:bloc_testofficialpub.dev
The official documentation of the blocTest parameters, MockBloc and whenListen.
- Bloc: testing guideofficialbloclibrary.dev
- Flutter: widget testsofficialdocs.flutter.dev
- package:bloc_concurrencyofficialpub.dev
Used together with the wait parameter when testing transformer behaviour.