bloc_test: blocTest, MockBloc, whenListen
package:bloc_test bloc/cubit testini deklarativ formaya salır. Əsas funksiya blocTest və onun parametrləri:
- `build` — test olunan bloc-u qurub qaytarır.
- `setUp` — bloc yaradılmadan əvvəl asılılıqları hazırlamaq.
- `seed` — bloc-a ilkin state "əkmək" (məsələn dolu siyahıdan başlamaq).
- `act` — bloc ilə qarşılıqlı əlaqə: event əlavə etmək, cubit metodu çağırmaq.
- `wait` — debounce kimi async əməliyyatlar üçün gözləmə müddəti.
- `skip` — gözləntilərdən əvvəl buraxılacaq state-lərin sayı (default 0).
- `expect` — gözlənilən state ardıcıllığı (matcher).
- `verify` —
expect-dən sonra əlavə yoxlamalar (məsələn repository bir dəfə çağırıldı). - `errors` — gözlənilən xətalar.
- `tearDown` — testdən sonra təmizləmə.
Əlavə alətlər: `MockBloc`/`MockCubit` — bloc-un stub versiyasını yaratmaq üçün; `whenListen` — bloc-un listen metoduna hazır cavab qurur və state xassəsini yayımlanan dəyərlərlə sinxronlaşdırır.
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: state ardıcıllığı və `verify` ilə əlavə yoxlama.
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);
});
}Widget testi: `MockBloc` və `whenListen` ilə UI-ı izolyasiya etmək.
| Nə yoxlanılır | Parametr / alət |
|---|---|
| State ardıcıllığı (loading → success) | `expect` |
| Müəyyən state-dən başlamaq | `seed` |
| Debounce/throttle davranışı | `wait` |
| İlk n state-i nəzərə almamaq | `skip` |
| Repository/servisin çağırılması | `verify` |
| Atılan xətalar | `errors` |
| UI-ı bloc-dan tam ayırmaq | `MockBloc` + `whenListen` |
expect ilə state ardıcıllığını yoxlamaq güclüdür, lakin kövrək ola bilər: state sinfinə yeni sahə əlavə edildikdə bütün testlər sınır. Praktik yanaşma — kritik sahələri matcher ilə yoxlamaq (isA<TodoState>().having((s) => s.status, 'status', TodoStatus.success)), tam bərabərliyi isə yalnız kiçik və sabit state-lərdə tələb etmək.
📚 Mənbələr və sənədlər
- package:bloc_testrəsmipub.dev
blocTest parametrlərinin, MockBloc və whenListen-in rəsmi sənədi.
- Bloc: test bələdçisirəsmibloclibrary.dev
- Flutter: widget testlərirəsmidocs.flutter.dev
- package:bloc_concurrencyrəsmipub.dev
Transformer davranışını test edərkən wait parametri ilə birlikdə istifadə olunur.