Testing Riverpod: ProviderContainer and overrides
Riverpod's testing model rests on two things: the container and overrides.
ProviderContainer.test()— per the docs it is part of Riverpod in 3.0: it creates a container for the test and disposes it automatically when the test ends. The docs' warning is blunt: do not share containers between tests, and inside tests useProviderContainer.test()rather thanProviderContainerdirectly.- `overrides` — any provider can be mocked with no extra setup:
ProviderContainer.test(overrides: [...]), orProviderScope(overrides: [...])in a widget test.
For reading: container.read(provider) gives the current value, while container.listen(provider, listener) creates a listener and prevents automatic disposal — the docs advise care with read on auto-disposed providers and suggest listen instead. To await an async provider's result, read provider.future.
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));
});
}A unit test: the container, an override and awaiting the async result.
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);
});
}A widget test: a fake dependency through `ProviderScope(overrides: ...)`.
| Goal | API |
|---|---|
| An isolated container for the test | `ProviderContainer.test()` — disposed automatically at the end of the test |
| Read the current value | `container.read(provider)` |
| Observe changes and prevent autoDispose | `container.listen(provider, (prev, next) {...})` |
| Await an async result | `await container.read(provider.future)` |
| Replace a dependency | `overrideWith(...)` / `overrideWithValue(...)` |
| Overriding in a widget test | `ProviderScope(overrides: [...])` |
An advantage worth stressing in an interview: with the Provider package a widget test has to rebuild the provider tree by hand, and with BLoC you write a MockBloc — whereas in Riverpod every provider can be overridden with no extra setup. That shortens test code especially when replacing the repository/service layer: the UI is untouched and only the dependency changes.
📚 Sources and documentation
- Testing your providersofficialriverpod.dev
ProviderContainer.test(), container.listen, overrides and the warning about not sharing containers.
- Overridesofficialriverpod.dev
- ProviderContainers and ProviderScopesofficialriverpod.dev
- Flutter: introduction to widget testingofficialdocs.flutter.dev