Sparround

Riverpod-un testi: ProviderContainer və override

Riverpod-un test modeli iki elementə söykənir: konteyneroverride.

  • ProviderContainer.test() — sənədə görə 3.0-da Riverpod-un bir hissəsidir: test üçün yeni konteyner yaradır və test bitəndə onu avtomatik sökür. Sənədin xəbərdarlığı birbaşadır: konteynerləri testlər arasında paylaşmayın; testin içində ProviderContainer-i birbaşa deyil, ProviderContainer.test() vasitəsilə istifadə edin.
  • `overrides` — istənilən provider əvəz oluna bilər, əlavə hazırlıq tələb olunmur: ProviderContainer.test(overrides: [...]) və ya widget testində ProviderScope(overrides: [...]).

Oxunuş üçün: container.read(provider) cari dəyəri verir; container.listen(provider, listener) isə dinləyici yaradır və avtomatik təmizlənmənin qarşısını alır — sənəd autoDispose provider-lərdə read-dən istifadə edərkən diqqətli olmağı və listen seçməyi tövsiyə edir. Async provider-in nəticəsini gözləmək üçün provider.future oxunur.

dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';

class FakeTodoRepository implements TodoRepository {
  FakeTodoRepository(this.items);
  final List<Todo> items;

  @override
  Future<List<Todo>> fetchAll() async => items;
}

void main() {
  test('todosProvider repository-dən gələn siyahını qaytarır', () async {
    final container = ProviderContainer.test(
      overrides: [
        // İstənilən provider override oluna bilər.
        todoRepositoryProvider.overrideWithValue(
          FakeTodoRepository([const Todo(id: '1', title: 'Süd al')]),
        ),
      ],
    );

    // Async provider-in nəticəsini future kimi gözləyirik.
    await expectLater(
      container.read(todosProvider.future),
      completion(hasLength(1)),
    );
  });

  test('add() siyahıya element əlavə edir', () async {
    final container = ProviderContainer.test(
      overrides: [
        todoRepositoryProvider.overrideWithValue(FakeTodoRepository(const [])),
      ],
    );

    // listen: autoDispose provider-in test müddətində yaşamasını təmin edir.
    final subscription = container.listen(todosProvider, (_, _) {});
    await container.read(todosProvider.future);

    await container.read(todosProvider.notifier).add('Yeni tapşırıq');

    expect(subscription.read().value, hasLength(1));
  });
}

Unit test: konteyner, override və async nəticənin gözlənilməsi.

dart
void main() {
  testWidgets('siyahı boş olduqda boş vəziyyət göstərilir', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [
          todoRepositoryProvider.overrideWithValue(FakeTodoRepository(const [])),
        ],
        child: const MaterialApp(home: TodoPage()),
      ),
    );

    // İlk frame: loading.
    expect(find.byType(CircularProgressIndicator), findsOneWidget);

    await tester.pumpAndSettle();

    expect(find.text('Hələ tapşırıq yoxdur'), findsOneWidget);
  });

  testWidgets('xəta halında yenidən yoxla düyməsi görünür', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [
          // Provider-i birbaşa xəta atan implementasiya ilə əvəz edirik.
          todosProvider.overrideWith(() => ThrowingTodosNotifier()),
        ],
        child: const MaterialApp(home: TodoPage()),
      ),
    );

    await tester.pumpAndSettle();

    expect(find.text('Yenidən yoxla'), findsOneWidget);
  });
}

Widget testi: `ProviderScope(overrides: ...)` ilə fake asılılıq.

MəqsədAPI
Test üçün izolyasiya olunmuş konteyner`ProviderContainer.test()` — test bitəndə avtomatik sökülür
Cari dəyəri oxumaq`container.read(provider)`
Dəyişiklikləri izləmək və autoDispose-un qarşısını almaq`container.listen(provider, (prev, next) {...})`
Async nəticəni gözləmək`await container.read(provider.future)`
Asılılığı əvəz etmək`overrideWith(...)` / `overrideWithValue(...)`
Widget testində əvəzləmə`ProviderScope(overrides: [...])`

Müsahibədə vurğulamağa dəyən üstünlük: Provider paketində widget testi üçün provider ağacını əl ilə qurmaq lazımdır, BLoC-da MockBloc yazılır — Riverpod-da isə hər provider heç bir əlavə hazırlıq olmadan override oluna bilir. Bu, xüsusilə repository/service qatını əvəz edərkən test kodunu qısaldır: UI toxunulmur, yalnız asılılıq dəyişir.

📚 Mənbələr və sənədlər